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
|