LCOV - code coverage report
Current view: top level - libcody - cody.hh (source / functions) Hit Total Coverage
Test: gcc.info Lines: 36 38 94.7 %
Date: 2023-07-19 08:18:47 Functions: 1 1 100.0 %

          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        2960 : inline Flags operator& (Flags a, Flags b)
     221             : {
     222        2960 :   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       41498 :   ~Packet ()
     287             :   {
     288       41498 :     Destroy ();
     289       33528 :   }
     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       30674 :   unsigned GetCode () const
     303             :   {
     304       30674 :     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       24302 :   size_t GetInteger () const
     327             :   {
     328       24302 :     return integer;
     329             :   }
     330             :   ///
     331             :   /// Return (a reference to) a string payload.  Undefined if the
     332             :   /// category is not STRING
     333             :   std::string const &GetString () const
     334             :   {
     335        3462 :     return string;
     336             :   }
     337             :   std::string &GetString ()
     338             :   {
     339        2882 :     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        2873 :   Client (Server *s)
     393        2873 :     : Client ()
     394             :   {
     395        2873 :     is_direct = true;
     396        2873 :     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          18 :     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        5706 :   bool IsDirect () const
     416             :   {
     417        5706 :     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        2815 :   Server *GetServer () const
     445             :   {
     446        2815 :     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        2882 :   Packet Connect (std::string const &agent, std::string const &ident)
     465             :   {
     466        2882 :     return Connect (agent.c_str (), ident.c_str (),
     467        2882 :                     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        1654 :   Packet ModuleCompiled (char const *str)
     518             :   {
     519        1654 :     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        2873 :   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        2815 :   Resolver *GetResolver () const
     694             :   {
     695        2815 :     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        6320 :   void PathnameResponse (std::string const &path)
     736             :   {
     737        6320 :     PathnameResponse (path.data (), path.size ());
     738        3447 :   }
     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

Generated by: LCOV version 1.16