xref: /netbsd/external/gpl3/gcc/dist/libcody/cody.hh (revision f0fbc68b)
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>
S2C(char const (& s)[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.
PrepareToWrite()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.
PrepareToRead()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.
EndLine()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.
Space()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
AppendWord(char const * str,bool maybe_quote=false,size_t len=~size_t (0))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
AppendWord(std::string const & str,bool maybe_quote=false)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
IsAtEnd() const162   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 
operator &(Flags a,Flags b)220 inline Flags operator& (Flags a, Flags b)
221 {
222   return Flags (unsigned (a) & unsigned (b));
223 }
operator |(Flags a,Flags b)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:
Packet(unsigned c,size_t i=0)255   Packet (unsigned c, size_t i = 0)
256     : integer (i), cat (INTEGER), code (c)
257   {
258   }
Packet(unsigned c,std::string && s)259   Packet (unsigned c, std::string &&s)
260     : string (std::move (s)), cat (STRING), code (c)
261   {
262   }
Packet(unsigned c,std::string const & s)263   Packet (unsigned c, std::string const &s)
264     : string (s), cat (STRING), code (c)
265   {
266   }
Packet(unsigned c,std::vector<std::string> && v)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
Packet(Packet && t)275   Packet (Packet &&t)
276   {
277     Create (std::move (t));
278   }
operator =(Packet && t)279   Packet &operator= (Packet &&t)
280   {
281     Destroy ();
282     Create (std::move (t));
283 
284     return *this;
285   }
~Packet()286   ~Packet ()
287   {
288     Destroy ();
289   }
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
GetCode() const302   unsigned GetCode () const
303   {
304     return code;
305   }
306   ///
307   /// Return the packet type
GetRequest() const308   unsigned GetRequest () const
309   {
310     return request;
311   }
SetRequest(unsigned r)312   void SetRequest (unsigned r)
313   {
314     request = r;
315   }
316   ///
317   /// Return the category of the packet's payload
GetCategory() const318   Category GetCategory () const
319   {
320     return cat;
321   }
322 
323 public:
324   ///
325   /// Return an integral payload.  Undefined if the category is not INTEGER
GetInteger() const326   size_t GetInteger () const
327   {
328     return integer;
329   }
330   ///
331   /// Return (a reference to) a string payload.  Undefined if the
332   /// category is not STRING
GetString() const333   std::string const &GetString () const
334   {
335     return string;
336   }
GetString()337   std::string &GetString ()
338   {
339     return string;
340   }
341   ///
342   /// Return (a reference to) a constant vector of strings payload.
343   /// Undefined if the category is not VECTOR
GetVector() const344   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
GetVector()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
Client(Server * s)392   Client (Server *s)
393     : Client ()
394   {
395     is_direct = true;
396     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
Client(int from,int to=-1)401   Client (int from, int to = -1)
402     : Client ()
403   {
404     fd.from = from;
405     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
IsDirect() const415   bool IsDirect () const
416   {
417     return is_direct;
418   }
419   ///
420   /// Successful handshake predicate
IsConnected() const421   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
GetFDRead() const430   int GetFDRead () const
431   {
432     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
GetFDWrite() const437   int GetFDWrite () const
438   {
439     return is_direct ? -1 : fd.to;
440   }
441   ///
442   /// Get the directly-connected server
443   /// @result the server, or nullptr if a communication connection
GetServer() const444   Server *GetServer () const
445   {
446     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
Connect(std::string const & agent,std::string const & ident)464   Packet Connect (std::string const &agent, std::string const &ident)
465   {
466     return Connect (agent.c_str (), ident.c_str (),
467 		    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 
ModuleExport(char const * str)483   Packet ModuleExport (char const *str)
484   {
485     return ModuleExport (str, Flags::None, ~size_t (0));
486   }
ModuleExport(std::string const & s,Flags flags=Flags::None)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 
ModuleImport(char const * str)499   Packet ModuleImport (char const *str)
500   {
501     return ModuleImport (str, Flags::None, ~size_t (0));
502   }
ModuleImport(std::string const & s,Flags flags=Flags::None)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 
ModuleCompiled(char const * str)517   Packet ModuleCompiled (char const *str)
518   {
519     return ModuleCompiled (str, Flags::None, ~size_t (0));
520   }
ModuleCompiled(std::string const & s,Flags flags=Flags::None)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 
IncludeTranslate(char const * str)534   Packet IncludeTranslate (char const *str)
535   {
536     return IncludeTranslate (str, Flags::None, ~size_t (0));
537   }
IncludeTranslate(std::string const & s,Flags flags=Flags::None)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
IsCorked() const555   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   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);
Server(Resolver * r,int from,int to=-1)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:
IsConnected() const669   bool IsConnected () const
670   {
671     return is_connected;
672   }
673 
674 public:
SetDirection(Direction d)675   void SetDirection (Direction d)
676   {
677     direction = d;
678   }
679 
680 public:
GetDirection() const681   Direction GetDirection () const
682   {
683     return direction;
684   }
GetFDRead() const685   int GetFDRead () const
686   {
687     return fd.from;
688   }
GetFDWrite() const689   int GetFDWrite () const
690   {
691     return fd.to;
692   }
GetResolver() const693   Resolver *GetResolver () const
694   {
695     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));
ErrorResponse(std::string const & error)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));
PathnameResponse(std::string const & path)735   void PathnameResponse (std::string const &path)
736   {
737     PathnameResponse (path.data (), path.size ());
738   }
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));
ConnectResponse(std::string const & agent)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).
Write()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.
PrepareToWrite()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)
Read()770   int Read ()
771   {
772     return read.Read (fd.from);
773   }
774   /// Initialize for reading a message block.  Enters READING state.
PrepareToRead()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
805