cody.hh 21 KB

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