Commit 8f42ae0d authored by Yann Garcia's avatar Yann Garcia
Browse files

Adding comments

parent 4622dc75
Loading
Loading
Loading
Loading
+108 −13
Original line number Diff line number Diff line
/*!
 * \file      async_process.hh
 * \brief     Header file for the asynchronous child-process manager.
 * \author    ETSI STF685
 * \copyright ETSI Copyright Notification
 *            No part may be reproduced except as authorized by written permission.
 *            The copyright and the foregoing restriction extend to reproduction in all media.
 *            All rights reserved.
 * \version   0.1
 */
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
@@ -15,42 +25,127 @@
#include <vector>
#include <optional>

/*!
 * \class async_process
 * \brief Manages the lifecycle of an asynchronous child process with piped I/O.
 *
 * Forks and executes an arbitrary command with full stdin/stdout/stderr pipe
 * support, an optional execution timeout, optional sudo elevation, and an
 * optional streaming output callback.  A background reader thread drains the
 * child's output pipes and invokes the callback (if set) for each chunk.
 *
 * Usage pattern:
 * \code
 * async_process proc;
 * proc.start("tcpdump", {"-i", "eth0"}, {});
 * // ... do work ...
 * proc.terminate();
 * proc.wait();
 * \endcode
 *
 * Instances are non-copyable; move semantics are not provided.
 */
class async_process {
public:
    /*!
     * \brief Callback type invoked for each chunk of child process output.
     * \param chunk    A view of the output chunk (stdout or stderr).
     * \param isStderr \c true if the chunk came from stderr, \c false for stdout.
     */
    using OutputCallback = std::function<void(std::string_view, bool isStderr)>;

    /*!
     * \struct Options
     * \brief Configuration options for \ref async_process::start().
     */
    struct Options {
        bool useSudo = false;
        std::string sudoPassword;   // only used if useSudo == true
        OutputCallback onOutput;    // optional callback for stdout/stderr chunks
        bool useSudo = false;          //!< Run the command under \c sudo if \c true.
        std::string sudoPassword;      //!< Password fed to sudo stdin; only used when \c useSudo is \c true.
        OutputCallback onOutput;       //!< Optional callback invoked for each stdout/stderr chunk.
    };

    /*! \brief Default constructor. */
    async_process() = default;

    /*! \brief Destructor — terminates the child process (SIGTERM) and waits for it to exit. */
    ~async_process() { terminate(); wait(); }

    async_process(const async_process&) = delete;
    async_process& operator=(const async_process&) = delete;

    /*!
     * \brief Fork and execute a command asynchronously.
     *
     * Starts the child process and, if \c opts.onOutput is set, launches a
     * background reader thread that drains stdout/stderr and invokes the callback.
     * Throws \c std::runtime_error on fork or pipe failure.
     * \param[in] command The executable path or name (resolved via \c PATH).
     * \param[in] args    Command-line arguments (argv[1..n]).
     * \param[in] opts    Execution options (sudo, output callback).
     * \param[in] timeout Maximum time to wait before the process is considered hung
     *                    (default 2 000 ms).  Currently informational only.
     */
    void start(const std::string& command, const std::vector<std::string>& args, Options opts, std::chrono::milliseconds timeout = std::chrono::milliseconds(2000));

    /*!
     * \brief Non-blocking check for child process exit.
     * \param[out] status The exit status if the child has exited.
     * \return \c true if the child has exited and \p status has been filled in.
     */
    bool pollExitStatus(int& status);

    /*!
     * \brief Block until the child process exits.
     * \return The child's exit status as returned by \c waitpid().
     */
    int wait();

    /*!
     * \brief Send a signal to the child and optionally wait for it to exit.
     * \param[in] signalNo Signal number to send (default \c SIGTERM).
     * \param[in] timeout  How long to wait for the child to exit after the signal
     *                     (default 5 000 ms).
     * \return The child's exit status, or -1 if the child was not running.
     */
    int terminate(int signalNo = SIGTERM, std::chrono::milliseconds timeout = std::chrono::milliseconds(5000));

    /*!
     * \brief Return whether the child process is currently running.
     * \return \c true if the child is alive, \c false if it has exited or was never started.
     */
    inline bool running() const noexcept { return running_ && !exited_; };
    inline void killForce() { terminate(SIGTERM); }; // Clean termination of the process, with SIGTERM signal

    /*! \brief Send SIGTERM to the child (clean shutdown request). */
    inline void killForce() { terminate(SIGTERM); };

    /*!
     * \brief Drain and return any buffered data from the child's stdout pipe.
     * \return All currently available stdout data as a string.
     */
    inline std::string readStdout() { return drainFd(stdoutPipe_[0]); };

    /*!
     * \brief Drain and return any buffered data from the child's stderr pipe.
     * \return All currently available stderr data as a string.
     */
    inline std::string readStderr() { return drainFd(stderrPipe_[0]); };

    /*!
     * \brief Return the PID of the child process.
     * \return The child's \c pid_t, or -1 if no process has been started.
     */
    inline pid_t pid() const noexcept { return pid_; };

private:
    pid_t pid_ = -1;
    bool running_ = false;
    bool exited_ = false;
    int exitStatus_;
    Options opts_;
    std::array<int, 2> stdoutPipe_{-1, -1};
    std::array<int, 2> stderrPipe_{-1, -1};
    std::array<int, 2> stdinPipe_{-1, -1};
    std::thread reader_;
    pid_t pid_ = -1;                          //!< Child process PID
    bool running_ = false;                    //!< True once start() succeeds
    bool exited_ = false;                     //!< True once waitpid() reports exit
    int exitStatus_;                          //!< Raw waitpid() exit status
    Options opts_;                            //!< Saved options from start()
    std::array<int, 2> stdoutPipe_{-1, -1};  //!< [read, write] pipe for child stdout
    std::array<int, 2> stderrPipe_{-1, -1};  //!< [read, write] pipe for child stderr
    std::array<int, 2> stdinPipe_{-1, -1};   //!< [read, write] pipe for child stdin
    std::thread reader_;                      //!< Background thread that drains output pipes

    static void setNonBlocking(int fd);
    static void closeIfOpen(int fd);
+139 −10
Original line number Diff line number Diff line
/*!
 * \file      http_codec.hh
 * \brief     Header file for the HTTP/1.1 message codec.
 * \author    ETSI STF685
 * \copyright ETSI Copyright Notification
 *            No part may be reproduced except as authorized by written permission.
 *            The copyright and the foregoing restriction extend to reproduction in all media.
 *            All rights reserved.
 * \version   0.1
 */
#pragma once

#include <memory>
@@ -31,23 +41,45 @@ namespace LibHttp__JsonMessageBodyTypes {
  class JsonBody;
} // namespace LibHttp__JsonMessageBodyTypes

/*!
 * \struct encoding_context
 * \brief  Transient state maintained while encoding a single HTTP message.
 *
 * Tracks whether a Content-Length header has already been written and what the
 * accumulated body length is, so the encoder can back-fill or omit the header
 * as required by RFC 7230.
 */
struct encoding_context {
  unsigned int  length;
  uint8_t is_content_length_present;
  unsigned int length;                   //!< Accumulated encoded body length (bytes).
  uint8_t      is_content_length_present; //!< Non-zero if Content-Length was already written.

  /*! \brief Default constructor — delegates to \c reset(). */
  encoding_context() { reset(); };

  /*! \brief Reset all fields to their initial (no-message) state. */
  void reset() {
    length                    = -1;
    is_content_length_present = 0x00;
  };
};

/*!
 * \struct decoding_context
 * \brief  Transient state maintained while decoding a single HTTP message.
 *
 * Tracks the expected body length (from Content-Length), whether the body
 * should be treated as raw binary, and whether chunked transfer encoding is
 * active, so the decoder can correctly delimit the message boundary.
 */
struct decoding_context {
  unsigned int  length;
  uint8_t is_binary;
  bool          chunked;
  unsigned int length;    //!< Expected body length from the Content-Length header (-1 if unknown).
  uint8_t      is_binary; //!< Non-zero if the body should be decoded as raw binary.
  bool         chunked;   //!< \c true if Transfer-Encoding: chunked was seen.

  /*! \brief Default constructor — delegates to \c reset(). */
  decoding_context() { reset(); };

  /*! \brief Reset all fields to their initial (no-message) state. */
  void reset() {
    length    = -1;
    is_binary = 0x00;
@@ -55,36 +87,133 @@ struct decoding_context {
  };
};

/*!
 * \class http_codec
 * \brief Base codec for encoding/decoding HTTP/1.1 messages and their entity bodies.
 *
 * Handles HTTP/1.1 framing (request-line or status-line, headers, body) and
 * dispatches body encoding/decoding to content-type-specific virtual methods
 * (binary, XML, JSON, HTML).  Subclasses override the \c encode_body_* /
 * \c decode_body_* methods to provide concrete payload serialisation.
 *
 * The set of active body codecs is configured at runtime via
 * \c set_payload_codecs().  Chunked transfer encoding and multi-buffer
 * reassembly are handled transparently during decoding.
 */
class http_codec : public codec_gen<LibHttp__TypesAndValues::HttpMessage, LibHttp__TypesAndValues::HttpMessage> {
  encoding_context                                                        _ec;
  decoding_context                                                        _dc;
  encoding_context _ec; //!< Per-message encoding state
  decoding_context _dc; //!< Per-message decoding state

protected:
  //! Map of content-type key → body codec instance used during body dispatch.
  std::map<std::string, std::unique_ptr<codec_gen<Record_Type, Record_Type>>> _codecs;
  std::vector<OCTETSTRING> _bufferized_buffers;
  unsigned int             _initial_content_length;
  unsigned int             _current_content_length;
  std::vector<OCTETSTRING> _bufferized_buffers;    //!< Reassembly buffer for fragmented HTTP bodies.
  unsigned int             _initial_content_length; //!< Content-Length value from the headers.
  unsigned int             _current_content_length; //!< Bytes accumulated so far during decoding.

public:
  /*! \brief Default constructor. */
  explicit http_codec() : codec_gen<LibHttp__TypesAndValues::HttpMessage, LibHttp__TypesAndValues::HttpMessage>(), _ec(), _dc(), _codecs(), _bufferized_buffers(), _initial_content_length{0}, _current_content_length{0} {};
  /*! \brief Destructor. */
  virtual ~http_codec(){};

  /*!
   * \brief Encode an \c HttpMessage value to an HTTP/1.1 octet string.
   * \param[in]  p_message The HTTP message (request or response) to encode.
   * \param[out] p_data    The encoded octet string.
   * \return 0 on success, -1 on failure.
   */
  virtual int encode(const LibHttp__TypesAndValues::HttpMessage &, OCTETSTRING &p_data);

  /*!
   * \brief Decode an HTTP/1.1 octet string into an \c HttpMessage value.
   * \param[in]  p_data    The raw octet string from the transport layer.
   * \param[out] p_message The decoded HTTP message.
   * \param[in]  params    Optional decoding parameters (may be NULL).
   * \return 0 on success, -1 on failure.
   */
  virtual int decode(const OCTETSTRING &p_data, LibHttp__TypesAndValues::HttpMessage &, params *params = NULL);

  /*!
   * \brief Configure the set of body codecs from a colon-separated descriptor string.
   * \param[in] p_codecs Codec descriptor (e.g. \c "json_codec:xml_codec").
   */
  void set_payload_codecs(const std::string& p_codecs);

protected: //! \protectedsection
  /*!
   * \brief Encode a binary entity body.
   * \param[in]  p_binary_body     The binary body value.
   * \param[out] p_encoding_buffer Output buffer to append encoded bytes to.
   * \param[in]  p_content_type    Content-Type string.
   * \return \c true on success, \c false if unsupported.
   */
  virtual bool encode_body_binary(const LibHttp__BinaryMessageBodyTypes::BinaryBody &p_binary_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type) {return false;};

  /*!
   * \brief Decode a binary entity body.
   * \param[in]  p_data         Raw body bytes.
   * \param[out] p_binary_body  Decoded binary body value.
   * \param[in]  p_content_type Content-Type string.
   * \return \c true on success, \c false if unsupported.
   */
  virtual bool decode_body_binary(const OCTETSTRING &p_data, LibHttp__BinaryMessageBodyTypes::BinaryBody &p_binary_body, const std::string& p_content_type) {return false;};

  /*!
   * \brief Encode an XML entity body.
   * \param[in]  p_xml_body        The XML body value.
   * \param[out] p_encoding_buffer Output buffer.
   * \param[in]  p_content_type    Content-Type string.
   * \return \c true on success, \c false if unsupported.
   */
  virtual bool encode_body_xml(const LibHttp__XmlMessageBodyTypes::XmlBody &p_xml_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type) {return false;};

  /*!
   * \brief Decode an XML entity body.
   * \param[in]  p_data         Raw body bytes.
   * \param[out] p_body         Decoded XML body value.
   * \param[in]  p_content_type Content-Type string.
   * \param[in]  p_params       Optional parameters.
   * \return \c true on success, \c false if unsupported.
   */
  virtual bool decode_body_xml(const OCTETSTRING &p_data, LibHttp__XmlMessageBodyTypes::XmlBody &p_body, const std::string& p_content_type, params* p_params) {return false;};

  /*!
   * \brief Encode an HTML/text entity body.
   * \param[in]  p_html_body       The HTML character string.
   * \param[out] p_encoding_buffer Output buffer.
   * \param[in]  p_content_type    Content-Type string.
   * \return \c true on success, \c false if unsupported.
   */
  virtual bool encode_body_html(const CHARSTRING &p_html_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type) {return false;};

  /*!
   * \brief Decode an HTML/text entity body.
   * \param[in]  p_data         Raw body bytes.
   * \param[out] p_html_body    Decoded HTML character string.
   * \param[in]  p_content_type Content-Type string.
   * \param[in]  p_params       Optional parameters.
   * \return \c true on success, \c false if unsupported.
   */
  virtual bool decode_body_html(const OCTETSTRING &p_data, CHARSTRING &p_html_body, const std::string& p_content_type, params* p_params);

  /*!
   * \brief Encode a JSON entity body.
   * \param[in]  p_json_body       The JSON body value.
   * \param[out] p_encoding_buffer Output buffer.
   * \param[in]  p_content_type    Content-Type string.
   * \return \c true on success, \c false if unsupported.
   */
  virtual bool encode_body_json(const LibHttp__JsonMessageBodyTypes::JsonBody &p_json_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type) {return false;};

  /*!
   * \brief Decode a JSON entity body.
   * \param[in]  p_data         Raw body bytes.
   * \param[out] p_json_body    Decoded JSON body value.
   * \param[in]  p_content_type Content-Type string.
   * \param[in]  p_params       Optional parameters.
   * \return \c true on success, \c false if unsupported.
   */
  virtual bool decode_body_json(const OCTETSTRING &p_data, LibHttp__JsonMessageBodyTypes::JsonBody &p_json_body, const std::string& p_content_type, params* p_params) {return false;};

private:
+35 −0
Original line number Diff line number Diff line
/*!
 * \file      json_codec.hh
 * \brief     Header file for the JSON HTTP message body codec.
 * \author    ETSI STF685
 * \copyright ETSI Copyright Notification
 *            No part may be reproduced except as authorized by written permission.
 *            The copyright and the foregoing restriction extend to reproduction in all media.
 *            All rights reserved.
 * \version   0.1
 */
#pragma once

#include "codec_gen.hh"
@@ -11,13 +21,38 @@ namespace LibHttp__JsonMessageBodyTypes {
  class JsonBody;
}

/*!
 * \class json_codec
 * \brief Codec for JSON-encoded HTTP message bodies.
 *
 * Encodes a TITAN \c JsonBody value to a UTF-8 JSON octet string and decodes
 * a UTF-8 JSON octet string back to a \c JsonBody value.  Registered with
 * \ref codec_stack_builder under the key \c "json_codec" and instantiated by
 * \c json_codec_factory when the layer stack descriptor includes that key.
 */
class json_codec: public codec_gen<LibHttp__JsonMessageBodyTypes::JsonBody, LibHttp__JsonMessageBodyTypes::JsonBody>
{
public:
  /*! \brief Default constructor. */
  explicit json_codec() : codec_gen<LibHttp__JsonMessageBodyTypes::JsonBody, LibHttp__JsonMessageBodyTypes::JsonBody>() { };
  /*! \brief Destructor. */
  virtual ~json_codec() { };

  /*!
   * \brief Encode a JSON message body to a UTF-8 octet string.
   * \param[in]  p_body The JSON body value to encode.
   * \param[out] data   The resulting UTF-8 JSON octet string.
   * \return 0 on success, -1 on failure.
   */
  virtual int encode (const LibHttp__JsonMessageBodyTypes::JsonBody&, OCTETSTRING& data);

  /*!
   * \brief Decode a UTF-8 JSON octet string into a JSON message body.
   * \param[in]  p_data   The JSON octet string to decode.
   * \param[out] p_body   The decoded JSON body value.
   * \param[in]  p_params Optional decoding parameters (may be NULL).
   * \return 0 on success, -1 on failure.
   */
  virtual int decode (const OCTETSTRING& p_data, LibHttp__JsonMessageBodyTypes::JsonBody&, params* p_params = NULL);

}; // End of class json_codec
+11 −0
Original line number Diff line number Diff line
/*!
 * \file      pcap_layer.hh
 * \brief     Platform-selector header for the pcap protocol layer.
 *
 * Includes the correct platform-specific pcap layer header:
 * - \c pcap_cygwin_layer.hh on Cygwin/Windows environments.
 * - \c pcap_linux_layer.hh  on all other (Linux/POSIX) environments.
 *
 * Consumers should always include this file rather than the platform-specific
 * variants directly.
 */
#if defined (__CYGWIN__)
 #include "pcap_cygwin_layer.hh"
#else