Branch data Line data Source code
1 : : // CODYlib -*- mode:c++ -*-
2 : : // Copyright (C) 2020 Nathan Sidwell, nathan@acm.org
3 : : // License: Apache v2.0
4 : :
5 : : #ifndef CODY_HH
6 : : #define CODY_HH 1
7 : :
8 : : // If the user specifies this as non-zero, it must be what we expect,
9 : : // generally only good for requesting no networking
10 : : #if !defined (CODY_NETWORKING)
11 : : // Have a known-good list of networking systems
12 : : #if defined (__unix__) || defined (__MACH__)
13 : : #define CODY_NETWORKING 1
14 : : #else
15 : : #define CODY_NETWORKING 0
16 : : #endif
17 : : #if 0 // For testing
18 : : #undef CODY_NETWORKING
19 : : #define CODY_NETWORKING 0
20 : : #endif
21 : : #endif
22 : :
23 : : // C++
24 : : #include <memory>
25 : : #include <string>
26 : : #include <vector>
27 : : // C
28 : : #include <cstddef>
29 : : // OS
30 : : #include <errno.h>
31 : : #include <sys/types.h>
32 : : #if CODY_NETWORKING
33 : : #include <sys/socket.h>
34 : : #endif
35 : :
36 : : namespace Cody {
37 : :
38 : : // Set version to 1, as this is completely incompatible with 0.
39 : : // Fortunately both versions 0 and 1 will recognize each other's HELLO
40 : : // messages sufficiently to error out
41 : : constexpr unsigned Version = 1;
42 : :
43 : : // FIXME: I guess we need a file-handle abstraction here
44 : : // Is windows DWORDPTR still?, or should it be FILE *? (ew).
45 : :
46 : : namespace Detail {
47 : :
48 : : // C++11 doesn't have utf8 character literals :(
49 : :
50 : : template<unsigned I>
51 : : constexpr char S2C (char const (&s)[I])
52 : : {
53 : : static_assert (I == 2, "only single octet strings may be converted");
54 : : return s[0];
55 : : }
56 : :
57 : : /// Internal buffering class. Used to concatenate outgoing messages
58 : : /// and Lex incoming ones.
59 : : class MessageBuffer
60 : : {
61 : : std::vector<char> buffer; ///< buffer holding the message
62 : : size_t lastBol = 0; ///< location of the most recent Beginning Of
63 : : ///< Line, or position we've readed when writing
64 : :
65 : : public:
66 : : MessageBuffer () = default;
67 : : ~MessageBuffer () = default;
68 : : MessageBuffer (MessageBuffer &&) = default;
69 : : MessageBuffer &operator= (MessageBuffer &&) = default;
70 : :
71 : : public:
72 : : ///
73 : : /// Finalize a buffer to be written. No more lines can be added to
74 : : /// the buffer. Use before a sequence of Write calls.
75 : : void PrepareToWrite ()
76 : : {
77 : : buffer.push_back (u8"\n"[0]);
78 : : lastBol = 0;
79 : : }
80 : : ///
81 : : /// Prepare a buffer for reading. Use before a sequence of Read calls.
82 : : void PrepareToRead ()
83 : : {
84 : : buffer.clear ();
85 : : lastBol = 0;
86 : : }
87 : :
88 : : public:
89 : : /// Begin a message line. Use before a sequence of Append and
90 : : /// related calls.
91 : : void BeginLine ();
92 : : /// End a message line. Use after a sequence of Append and related calls.
93 : : void EndLine () {}
94 : :
95 : : public:
96 : : /// Append a string to the current line. No whitespace is prepended
97 : : /// or appended.
98 : : ///
99 : : /// @param str the string to be written
100 : : /// @param maybe_quote indicate if there's a possibility the string
101 : : /// contains characters that need quoting. Defaults to false.
102 : : /// It is always safe to set
103 : : /// this true, but that causes an additional scan of the string.
104 : : /// @param len The length of the string. If not specified, strlen
105 : : /// is used to find the length.
106 : : void Append (char const *str, bool maybe_quote = false,
107 : : size_t len = ~size_t (0));
108 : :
109 : : ///
110 : : /// Add whitespace word separator. Multiple adjacent whitespace is fine.
111 : : void Space ()
112 : : {
113 : : Append (Detail::S2C(u8" "));
114 : : }
115 : :
116 : : public:
117 : : /// Add a word as with Append, but prefixing whitespace to make a
118 : : /// separate word
119 : : void AppendWord (char const *str, bool maybe_quote = false,
120 : : size_t len = ~size_t (0))
121 : : {
122 : : if (buffer.size () != lastBol)
123 : : Space ();
124 : : Append (str, maybe_quote, len);
125 : : }
126 : : /// Add a word as with AppendWord
127 : : /// @param str the string to append
128 : : /// @param maybe_quote string might need quoting, as for Append
129 : : void AppendWord (std::string const &str, bool maybe_quote = false)
130 : : {
131 : : AppendWord (str.data (), maybe_quote, str.size ());
132 : : }
133 : : ///
134 : : /// Add an integral value, prepending a space.
135 : : void AppendInteger (unsigned u);
136 : :
137 : : private:
138 : : /// Append a literal character.
139 : : /// @param c character to append
140 : : void Append (char c);
141 : :
142 : : public:
143 : : /// Lex the next input line into a vector of words.
144 : : /// @param words filled with a vector of lexed strings
145 : : /// @result 0 if no errors, an errno value on lexxing error such as
146 : : /// there being no next line (ENOENT), or malformed quoting (EINVAL)
147 : : int Lex (std::vector<std::string> &words);
148 : :
149 : : public:
150 : : /// Append the most-recently lexxed line to a string. May be useful
151 : : /// in error messages. The unparsed line is appended -- before any
152 : : /// unquoting.
153 : : /// If we had c++17 string_view, we'd simply return a view of the
154 : : /// line, and leave it to the caller to do any concatenation.
155 : : /// @param l string to-which the lexxed line is appended.
156 : : void LexedLine (std::string &l);
157 : :
158 : : public:
159 : : /// Detect if we have reached the end of the input buffer.
160 : : /// I.e. there are no more lines to Lex
161 : : /// @result True if at end
162 : : bool IsAtEnd () const
163 : : {
164 : : return lastBol == buffer.size ();
165 : : }
166 : :
167 : : public:
168 : : /// Read from end point into a read buffer, as with read(2). This will
169 : : /// not block , unless FD is blocking, and there is nothing
170 : : /// immediately available.
171 : : /// @param fd file descriptor to read from. This may be a regular
172 : : /// file, pipe or socket.
173 : : /// @result on error returns errno. If end of file occurs, returns
174 : : /// -1. At end of message returns 0. If there is more needed
175 : : /// returns EAGAIN (or possibly EINTR). If the message is
176 : : /// malformed, returns EINVAL.
177 : : int Read (int fd) noexcept;
178 : :
179 : : public:
180 : : /// Write to an end point from a write buffer, as with write(2). As
181 : : /// with Read, this will not usually block.
182 : : /// @param fd file descriptor to write to. This may be a regular
183 : : /// file, pipe or socket.
184 : : /// @result on error returns errno.
185 : : /// At end of message returns 0. If there is more to write
186 : : /// returns EAGAIN (or possibly EINTR).
187 : : int Write (int fd) noexcept;
188 : : };
189 : :
190 : : ///
191 : : /// Request codes. Perhaps this should be exposed? These are likely
192 : : /// useful to servers that queue requests.
193 : : enum RequestCode
194 : : {
195 : : RC_CONNECT,
196 : : RC_MODULE_REPO,
197 : : RC_MODULE_EXPORT,
198 : : RC_MODULE_IMPORT,
199 : : RC_MODULE_COMPILED,
200 : : RC_INCLUDE_TRANSLATE,
201 : : RC_HWM
202 : : };
203 : :
204 : : /// Internal file descriptor tuple. It's used as an anonymous union member.
205 : : struct FD
206 : : {
207 : : int from; ///< Read from this FD
208 : : int to; ///< Write to this FD
209 : : };
210 : :
211 : : }
212 : :
213 : : // Flags for various requests
214 : : enum class Flags : unsigned
215 : : {
216 : : None,
217 : : NameOnly = 1<<0, // Only querying for CMI names, not contents
218 : : };
219 : :
220 : 4140 : inline Flags operator& (Flags a, Flags b)
221 : : {
222 : 4140 : return Flags (unsigned (a) & unsigned (b));
223 : : }
224 : : inline Flags operator| (Flags a, Flags b)
225 : : {
226 : : return Flags (unsigned (a) | unsigned (b));
227 : : }
228 : :
229 : : ///
230 : : /// Response data for a request. Returned by Client's request calls,
231 : : /// which return a single Packet. When the connection is Corked, the
232 : : /// Uncork call will return a vector of Packets.
233 : : class Packet
234 : : {
235 : : public:
236 : : ///
237 : : /// Packet is a variant structure. These are the possible content types.
238 : : enum Category { INTEGER, STRING, VECTOR};
239 : :
240 : : private:
241 : : // std:variant is a C++17 thing, so we're doing this ourselves.
242 : : union
243 : : {
244 : : size_t integer; ///< Integral value
245 : : std::string string; ///< String value
246 : : std::vector<std::string> vector; ///< Vector of string value
247 : : };
248 : : Category cat : 2; ///< Discriminator
249 : :
250 : : private:
251 : : unsigned short code = 0; ///< Packet type
252 : : unsigned short request = 0;
253 : :
254 : : public:
255 : : Packet (unsigned c, size_t i = 0)
256 : : : integer (i), cat (INTEGER), code (c)
257 : : {
258 : : }
259 : : Packet (unsigned c, std::string &&s)
260 : : : string (std::move (s)), cat (STRING), code (c)
261 : : {
262 : : }
263 : : Packet (unsigned c, std::string const &s)
264 : : : string (s), cat (STRING), code (c)
265 : : {
266 : : }
267 : : Packet (unsigned c, std::vector<std::string> &&v)
268 : : : vector (std::move (v)), cat (VECTOR), code (c)
269 : : {
270 : : }
271 : : // No non-move constructor from a vector. You should not be doing
272 : : // that.
273 : :
274 : : // Only move constructor and move assignment
275 : : Packet (Packet &&t)
276 : : {
277 : : Create (std::move (t));
278 : : }
279 : : Packet &operator= (Packet &&t)
280 : : {
281 : : Destroy ();
282 : : Create (std::move (t));
283 : :
284 : : return *this;
285 : : }
286 : 59632 : ~Packet ()
287 : : {
288 : 59632 : Destroy ();
289 : 48600 : }
290 : :
291 : : private:
292 : : ///
293 : : /// Variant move creation from another packet
294 : : void Create (Packet &&t);
295 : : ///
296 : : /// Variant destruction
297 : : void Destroy ();
298 : :
299 : : public:
300 : : ///
301 : : /// Return the packet type
302 : 44591 : unsigned GetCode () const
303 : : {
304 : 44591 : return code;
305 : : }
306 : : ///
307 : : /// Return the packet type
308 : : unsigned GetRequest () const
309 : : {
310 : : return request;
311 : : }
312 : : void SetRequest (unsigned r)
313 : : {
314 : : request = r;
315 : : }
316 : : ///
317 : : /// Return the category of the packet's payload
318 : : Category GetCategory () const
319 : : {
320 : : return cat;
321 : : }
322 : :
323 : : public:
324 : : ///
325 : : /// Return an integral payload. Undefined if the category is not INTEGER
326 : 35715 : size_t GetInteger () const
327 : : {
328 : 35715 : return integer;
329 : : }
330 : : ///
331 : : /// Return (a reference to) a string payload. Undefined if the
332 : : /// category is not STRING
333 : 4773 : std::string const &GetString () const
334 : : {
335 : 4776 : return string;
336 : : }
337 : : std::string &GetString ()
338 : : {
339 : 4056 : return string;
340 : : }
341 : : ///
342 : : /// Return (a reference to) a constant vector of strings payload.
343 : : /// Undefined if the category is not VECTOR
344 : : std::vector<std::string> const &GetVector () const
345 : : {
346 : : return vector;
347 : : }
348 : : ///
349 : : /// Return (a reference to) a non-conatant vector of strings payload.
350 : : /// Undefined if the category is not VECTOR
351 : : std::vector<std::string> &GetVector ()
352 : : {
353 : : return vector;
354 : : }
355 : : };
356 : :
357 : : class Server;
358 : :
359 : : ///
360 : : /// Client-side (compiler) object.
361 : : class Client
362 : : {
363 : : public:
364 : : /// Response packet codes
365 : : enum PacketCode
366 : : {
367 : : PC_CORKED, ///< Messages are corked
368 : : PC_CONNECT, ///< Packet is integer version
369 : : PC_ERROR, ///< Packet is error string
370 : : PC_OK,
371 : : PC_BOOL,
372 : : PC_PATHNAME
373 : : };
374 : :
375 : : private:
376 : : Detail::MessageBuffer write; ///< Outgoing write buffer
377 : : Detail::MessageBuffer read; ///< Incoming read buffer
378 : : std::string corked; ///< Queued request tags
379 : : union
380 : : {
381 : : Detail::FD fd; ///< FDs connecting to server
382 : : Server *server; ///< Directly connected server
383 : : };
384 : : bool is_direct = false; ///< Discriminator
385 : : bool is_connected = false; /// Connection handshake succesful
386 : :
387 : : private:
388 : : Client ();
389 : : public:
390 : : /// Direct connection constructor.
391 : : /// @param s Server to directly connect
392 : 4047 : Client (Server *s)
393 : 4047 : : Client ()
394 : : {
395 : 4047 : is_direct = true;
396 : 4047 : server = s;
397 : : }
398 : : /// Communication connection constructor
399 : : /// @param from file descriptor to read from
400 : : /// @param to file descriptor to write to, defaults to from
401 : 9 : Client (int from, int to = -1)
402 : 9 : : Client ()
403 : : {
404 : 9 : fd.from = from;
405 : 9 : fd.to = to < 0 ? from : to;
406 : : }
407 : : ~Client ();
408 : : // We have to provide our own move variants, because of the variant member.
409 : : Client (Client &&);
410 : : Client &operator= (Client &&);
411 : :
412 : : public:
413 : : ///
414 : : /// Direct connection predicate
415 : 7964 : bool IsDirect () const
416 : : {
417 : 7964 : return is_direct;
418 : : }
419 : : ///
420 : : /// Successful handshake predicate
421 : : bool IsConnected () const
422 : : {
423 : : return is_connected;
424 : : }
425 : :
426 : : public:
427 : : ///
428 : : /// Get the read FD
429 : : /// @result the FD to read from, -1 if a direct connection
430 : 0 : int GetFDRead () const
431 : : {
432 : 0 : return is_direct ? -1 : fd.from;
433 : : }
434 : : ///
435 : : /// Get the write FD
436 : : /// @result the FD to write to, -1 if a direct connection
437 : 9 : int GetFDWrite () const
438 : : {
439 : 9 : return is_direct ? -1 : fd.to;
440 : : }
441 : : ///
442 : : /// Get the directly-connected server
443 : : /// @result the server, or nullptr if a communication connection
444 : 3899 : Server *GetServer () const
445 : : {
446 : 3899 : return is_direct ? server : nullptr;
447 : : }
448 : :
449 : : public:
450 : : ///
451 : : /// Perform connection handshake. All othe requests will result in
452 : : /// errors, until handshake is succesful.
453 : : /// @param agent compiler identification
454 : : /// @param ident compilation identifiation (maybe nullptr)
455 : : /// @param alen length of agent string, if known
456 : : /// @param ilen length of ident string, if known
457 : : /// @result packet indicating success (or deferrment) of the
458 : : /// connection, payload is optional flags
459 : : Packet Connect (char const *agent, char const *ident,
460 : : size_t alen = ~size_t (0), size_t ilen = ~size_t (0));
461 : : /// std::string wrapper for connection
462 : : /// @param agent compiler identification
463 : : /// @param ident compilation identification
464 : 4056 : Packet Connect (std::string const &agent, std::string const &ident)
465 : : {
466 : 4056 : return Connect (agent.c_str (), ident.c_str (),
467 : 4056 : agent.size (), ident.size ());
468 : : }
469 : :
470 : : public:
471 : : /// Request compiler module repository
472 : : /// @result packet indicating repo
473 : : Packet ModuleRepo ();
474 : :
475 : : public:
476 : : /// Inform of compilation of a named module interface or partition,
477 : : /// or a header unit
478 : : /// @param str module or header-unit
479 : : /// @param len name length, if known
480 : : /// @result CMI name (or deferrment/error)
481 : : Packet ModuleExport (char const *str, Flags flags, size_t len = ~size_t (0));
482 : :
483 : : Packet ModuleExport (char const *str)
484 : : {
485 : : return ModuleExport (str, Flags::None, ~size_t (0));
486 : : }
487 : : Packet ModuleExport (std::string const &s, Flags flags = Flags::None)
488 : : {
489 : : return ModuleExport (s.c_str (), flags, s.size ());
490 : : }
491 : :
492 : : public:
493 : : /// Importation of a module, partition or header-unit
494 : : /// @param str module or header-unit
495 : : /// @param len name length, if known
496 : : /// @result CMI name (or deferrment/error)
497 : : Packet ModuleImport (char const *str, Flags flags, size_t len = ~size_t (0));
498 : :
499 : : Packet ModuleImport (char const *str)
500 : : {
501 : : return ModuleImport (str, Flags::None, ~size_t (0));
502 : : }
503 : : Packet ModuleImport (std::string const &s, Flags flags = Flags::None)
504 : : {
505 : : return ModuleImport (s.c_str (), flags, s.size ());
506 : : }
507 : :
508 : : public:
509 : : /// Successful compilation of a module interface, partition or
510 : : /// header-unit. Must have been preceeded by a ModuleExport
511 : : /// request.
512 : : /// @param str module or header-unit
513 : : /// @param len name length, if known
514 : : /// @result OK (or deferment/error)
515 : : Packet ModuleCompiled (char const *str, Flags flags, size_t len = ~size_t (0));
516 : :
517 : 2244 : Packet ModuleCompiled (char const *str)
518 : : {
519 : 2244 : return ModuleCompiled (str, Flags::None, ~size_t (0));
520 : : }
521 : : Packet ModuleCompiled (std::string const &s, Flags flags = Flags::None)
522 : : {
523 : : return ModuleCompiled (s.c_str (), flags, s.size ());
524 : : }
525 : :
526 : : /// Include translation query.
527 : : /// @param str header unit name
528 : : /// @param len name length, if known
529 : : /// @result Packet indicating include translation boolean, or CMI
530 : : /// name (or deferment/error)
531 : : Packet IncludeTranslate (char const *str, Flags flags,
532 : : size_t len = ~size_t (0));
533 : :
534 : : Packet IncludeTranslate (char const *str)
535 : : {
536 : : return IncludeTranslate (str, Flags::None, ~size_t (0));
537 : : }
538 : : Packet IncludeTranslate (std::string const &s, Flags flags = Flags::None)
539 : : {
540 : : return IncludeTranslate (s.c_str (), flags, s.size ());
541 : : }
542 : :
543 : : public:
544 : : /// Cork the connection. All requests are queued up. Each request
545 : : /// call will return a PC_CORKED packet.
546 : : void Cork ();
547 : :
548 : : /// Uncork the connection. All queued requests are sent to the
549 : : /// server, and a block of responses waited for.
550 : : /// @result A vector of packets, containing the in-order responses to the
551 : : /// queued requests.
552 : : std::vector<Packet> Uncork ();
553 : : ///
554 : : /// Indicate corkedness of connection
555 : : bool IsCorked () const
556 : : {
557 : : return !corked.empty ();
558 : : }
559 : :
560 : : private:
561 : : Packet ProcessResponse (std::vector<std::string> &, unsigned code,
562 : : bool isLast);
563 : : Packet MaybeRequest (unsigned code);
564 : : int CommunicateWithServer ();
565 : : };
566 : :
567 : : /// This server-side class is used to resolve requests from one or
568 : : /// more clients. You are expected to derive from it and override the
569 : : /// virtual functions it provides. The connection resolver may return
570 : : /// a different resolved object to service the remainder of the
571 : : /// connection -- for instance depending on the compiler that is
572 : : /// making the requests.
573 : : class Resolver
574 : : {
575 : : public:
576 : 4047 : Resolver () = default;
577 : : virtual ~Resolver ();
578 : :
579 : : protected:
580 : : /// Mapping from a module or header-unit name to a CMI file name.
581 : : /// @param module module name
582 : : /// @result CMI name
583 : : virtual std::string GetCMIName (std::string const &module);
584 : :
585 : : /// Return the CMI file suffix to use
586 : : /// @result CMI suffix, a statically allocated string
587 : : virtual char const *GetCMISuffix ();
588 : :
589 : : public:
590 : : /// When the requests of a directly-connected server are processed,
591 : : /// we may want to wait for the requests to complete (for instance a
592 : : /// set of subjobs).
593 : : /// @param s directly connected server.
594 : : virtual void WaitUntilReady (Server *s);
595 : :
596 : : public:
597 : : /// Provide an error response.
598 : : /// @param s the server to provide the response to.
599 : : /// @param msg the error message
600 : : virtual void ErrorResponse (Server *s, std::string &&msg);
601 : :
602 : : public:
603 : : /// Connection handshake. Provide response to server and return new
604 : : /// (or current) resolver, or nullptr.
605 : : /// @param s server to provide response to
606 : : /// @param version the client's version number
607 : : /// @param agent the client agent (compiler identification)
608 : : /// @param ident the compilation identification (may be empty)
609 : : /// @result nullptr in the case of an error. An error response will
610 : : /// be sent. If handing off to another resolver, return that,
611 : : /// otherwise this
612 : : virtual Resolver *ConnectRequest (Server *s, unsigned version,
613 : : std::string &agent, std::string &ident);
614 : :
615 : : public:
616 : : // return 0 on ok, ERRNO on failure, -1 on unspecific error
617 : : virtual int ModuleRepoRequest (Server *s);
618 : :
619 : : virtual int ModuleExportRequest (Server *s, Flags flags,
620 : : std::string &module);
621 : : virtual int ModuleImportRequest (Server *s, Flags flags,
622 : : std::string &module);
623 : : virtual int ModuleCompiledRequest (Server *s, Flags flags,
624 : : std::string &module);
625 : : virtual int IncludeTranslateRequest (Server *s, Flags flags,
626 : : std::string &include);
627 : : };
628 : :
629 : :
630 : : /// This server-side (build system) class handles a single connection
631 : : /// to a client. It has 3 states, READING:accumulating a message
632 : : /// block froma client, WRITING:writing a message block to a client
633 : : /// and PROCESSING:resolving requests. If the server does not spawn
634 : : /// jobs to build needed artifacts, the PROCESSING state will be brief.
635 : : class Server
636 : : {
637 : : public:
638 : : enum Direction
639 : : {
640 : : READING, // Server is waiting for completion of a (set of)
641 : : // requests from client. The next state will be PROCESSING.
642 : : WRITING, // Server is writing a (set of) responses to client.
643 : : // The next state will be READING.
644 : : PROCESSING // Server is processing client request(s). The next
645 : : // state will be WRITING.
646 : : };
647 : :
648 : : private:
649 : : Detail::MessageBuffer write;
650 : : Detail::MessageBuffer read;
651 : : Resolver *resolver;
652 : : Detail::FD fd;
653 : : bool is_connected = false;
654 : : Direction direction : 2;
655 : :
656 : : public:
657 : : Server (Resolver *r);
658 : : Server (Resolver *r, int from, int to = -1)
659 : : : Server (r)
660 : : {
661 : : fd.from = from;
662 : : fd.to = to >= 0 ? to : from;
663 : : }
664 : : ~Server ();
665 : : Server (Server &&);
666 : : Server &operator= (Server &&);
667 : :
668 : : public:
669 : : bool IsConnected () const
670 : : {
671 : : return is_connected;
672 : : }
673 : :
674 : : public:
675 : : void SetDirection (Direction d)
676 : : {
677 : : direction = d;
678 : : }
679 : :
680 : : public:
681 : : Direction GetDirection () const
682 : : {
683 : : return direction;
684 : : }
685 : : int GetFDRead () const
686 : : {
687 : : return fd.from;
688 : : }
689 : : int GetFDWrite () const
690 : : {
691 : : return fd.to;
692 : : }
693 : 3899 : Resolver *GetResolver () const
694 : : {
695 : 3899 : return resolver;
696 : : }
697 : :
698 : : public:
699 : : /// Process requests from a directly-connected client. This is a
700 : : /// small wrapper around ProcessRequests, with some buffer swapping
701 : : /// for communication. It is expected that such processessing is
702 : : /// immediate.
703 : : /// @param from message block from client
704 : : /// @param to message block to client
705 : : void DirectProcess (Detail::MessageBuffer &from, Detail::MessageBuffer &to);
706 : :
707 : : public:
708 : : /// Process the messages queued in the read buffer. We enter the
709 : : /// PROCESSING state, and each message line causes various resolver
710 : : /// methods to be called. Once processed, the server may need to
711 : : /// wait for all the requests to be ready, or it may be able to
712 : : /// immediately write responses back.
713 : : void ProcessRequests ();
714 : :
715 : : public:
716 : : /// Accumulate an error response.
717 : : /// @param error the error message to encode
718 : : /// @param elen length of error, if known
719 : : void ErrorResponse (char const *error, size_t elen = ~size_t (0));
720 : : void ErrorResponse (std::string const &error)
721 : : {
722 : : ErrorResponse (error.data (), error.size ());
723 : : }
724 : :
725 : : /// Accumulate an OK response
726 : : void OKResponse ();
727 : :
728 : : /// Accumulate a boolean response
729 : : void BoolResponse (bool);
730 : :
731 : : /// Accumulate a pathname response
732 : : /// @param path (may be nullptr, or empty)
733 : : /// @param rlen length, if known
734 : : void PathnameResponse (char const *path, size_t plen = ~size_t (0));
735 : 8808 : void PathnameResponse (std::string const &path)
736 : : {
737 : 8808 : PathnameResponse (path.data (), path.size ());
738 : 4761 : }
739 : :
740 : : public:
741 : : /// Accumulate a (successful) connection response
742 : : /// @param agent the server-side agent
743 : : /// @param alen agent length, if known
744 : : void ConnectResponse (char const *agent, size_t alen = ~size_t (0));
745 : : void ConnectResponse (std::string const &agent)
746 : : {
747 : : ConnectResponse (agent.data (), agent.size ());
748 : : }
749 : :
750 : : public:
751 : : /// Write message block to client. Semantics as for
752 : : /// MessageBuffer::Write.
753 : : /// @result errno or completion (0).
754 : : int Write ()
755 : : {
756 : : return write.Write (fd.to);
757 : : }
758 : : /// Initialize for writing a message block. All responses to the
759 : : /// incomping message block must be complete Enters WRITING state.
760 : : void PrepareToWrite ()
761 : : {
762 : : write.PrepareToWrite ();
763 : : direction = WRITING;
764 : : }
765 : :
766 : : public:
767 : : /// Read message block from client. Semantics as for
768 : : /// MessageBuffer::Read.
769 : : /// @result errno, eof (-1) or completion (0)
770 : : int Read ()
771 : : {
772 : : return read.Read (fd.from);
773 : : }
774 : : /// Initialize for reading a message block. Enters READING state.
775 : : void PrepareToRead ()
776 : : {
777 : : read.PrepareToRead ();
778 : : direction = READING;
779 : : }
780 : : };
781 : :
782 : : // Helper network stuff
783 : :
784 : : #if CODY_NETWORKING
785 : : // Socket with specific address
786 : : int OpenSocket (char const **, sockaddr const *sock, socklen_t len);
787 : : int ListenSocket (char const **, sockaddr const *sock, socklen_t len,
788 : : unsigned backlog);
789 : :
790 : : // Local domain socket (eg AF_UNIX)
791 : : int OpenLocal (char const **, char const *name);
792 : : int ListenLocal (char const **, char const *name, unsigned backlog = 0);
793 : :
794 : : // ipv6 socket
795 : : int OpenInet6 (char const **e, char const *name, int port);
796 : : int ListenInet6 (char const **, char const *name, int port,
797 : : unsigned backlog = 0);
798 : : #endif
799 : :
800 : : // FIXME: Mapping file utilities?
801 : :
802 : : }
803 : :
804 : : #endif // CODY_HH
|