curl-fuzzer C++ reference
Loading...
Searching...
No Matches
proto_fuzzer::PingpongMockServer Class Referenceabstract

Drives one control socketpair that speaks a line-oriented command/response protocol. More...

#include <pingpong_mock_server.h>

Inheritance diagram for proto_fuzzer::PingpongMockServer:
proto_fuzzer::MockServerBase proto_fuzzer::IncomingDataObserver proto_fuzzer::DictMockServer proto_fuzzer::ImapMockServer proto_fuzzer::Pop3MockServer proto_fuzzer::RtspMockServer proto_fuzzer::SmtpMockServer proto_fuzzer::ImapsMockServer proto_fuzzer::Pop3sMockServer proto_fuzzer::SmtpsMockServer

Public Member Functions

 ~PingpongMockServer () override
 Release the server-owned socketpair half after curl has returned its client descriptor.
const std::string & control_transcript () const
 Expose the bounded command capture from the most recent drive so tests can verify protocol states without coupling assertions to curl debug output.
const std::string & uploaded_data () const
 Expose a bounded prefix of bytes drained during the most recent body phase while continuing to drain every client byte, so test observability cannot create backpressure.
std::size_t active_pollset_probe_count () const
 Report how many requested zero-timeout multi-poll probes ran during the most recent drive.
std::size_t writable_pollset_probe_count () const
 Report how often curl retained writable interest while the peer held an incomplete control command.
Public Member Functions inherited from proto_fuzzer::MockServerBase
virtual ~MockServerBase ()
 Out-of-line destructor so MockConnection can stay forward-declared in the base header (its complete type is only needed where unique_ptr is instantiated for destruction).
virtual void ObserveState ()
 Default no-op for peers without protocol-specific observations.
virtual void Install (CURL *easy)
 Install the common OPENSOCKETFUNCTION / OPENSOCKETDATA / SOCKOPTFUNCTION callbacks on 'easy'.
virtual void ConfigureRequestData (ScenarioRequestData *request_data)
 Bind protocol-specific work to the request-data callbacks after their per-scenario state has been constructed.
CURLcode DriveScenario (CURL *easy, const curl::fuzzer::proto::Scenario &scenario)
 Run 'scenario' to completion on 'easy': allocate a multi, attach 'easy', delegate protocol-specific work to RunLoop, consume its completion message, and clean up.
virtual CURLcode DriveEasyScenario (CURL *easy, const curl::fuzzer::proto::Scenario &scenario, bool use_events=false)
 Run through the public easy entrypoint when a protocol mock can preload all peer work before curl takes control.
virtual ConnectOnlyRunStats DriveConnectOnlyScenario (CURL *easy, const curl::fuzzer::proto::Scenario &scenario)
 Establish a CONNECT_ONLY transport, then perform bounded direct I/O.
void SetMultiObserver (MultiObserver observer)
 Register an observer invoked with the live multi handle after 'easy' is attached and before the drive loop starts.
MockConnection * connection ()

Protected Member Functions

 PingpongMockServer (MultiDrivePolicy drive_policy=MultiDrivePolicy::kPerform)
 Construct the shared transport state without a borrowed protobuf or open socketpair.
virtual std::unique_ptr< MockConnection > CreateConnection ()
 Create the default plaintext transport.
virtual void HandleLine (std::string_view line)=0
 Answer one complete, newline-terminated command line.
void BeginMarkerBody (std::string_view terminator)
 Enter marker-terminated body mode.
void BeginLiteralBody (std::size_t length)
 Enter length-announced literal body mode.
void BeginExactBody (std::size_t length)
 Enter exact-length body mode.
void BeginOpaqueDrain ()
 Enter an opaque drain after a transport upgrade.
virtual void HandleBodyComplete ()
 Called after a body phase reached its terminator and the parser returned to command mode.
virtual void QueueShutdownReply ()
 Queue protocol-specific teardown liveness bytes before the control socket is half-closed.
virtual void ResetProtocolState ()
 Reset protocol-specific parser state for a new drive.
curl_socket_t HandleOpenSocket (curlsocktype purpose=CURLSOCKTYPE_IPCXN, struct curl_sockaddr *address=nullptr) override
 Create the single control socketpair and queue the server greeting.
void RunLoop (CURLM *multi, CURL *easy, const curl::fuzzer::proto::Scenario &scenario) override
 Alternate curl transitions with immediate peer service until the transfer completes or deterministic idle/operation caps win.
void HandleDetachedMulti (CurlMultiPtr multi) override
 Give curl's graceful shutdown one last chance to emit its teardown command while the peer still owns its read half, then release the multi as the base class would.
void ObserveIncomingData (const unsigned char *data, std::size_t size) override
 Append decoded application bytes to the pending parser buffer.
const curl::fuzzer::proto::Scenario * scenario () const
 Borrowed scenario for the synchronous drive, or nullptr outside RunLoop().
const std::string * NextControlReply ()
 Return the next command-aligned response within the shared response-count budget.
bool WriteControlBytes (std::string_view bytes)
 Keep failed peer writes local to the mock.
bool WriteNextReply ()
 Consume the next scripted reply.
void ShutdownControlWrite ()
 Half-close the server-to-client direction while retaining the read half.
Protected Member Functions inherited from proto_fuzzer::MockServerBase
 MockServerBase (MultiDrivePolicy drive_policy=MultiDrivePolicy::kPerform)
 Construct an empty base instance with a fixed multi-drive policy.
virtual SocketSetupDisposition GetSocketSetupDisposition (curl_socket_t curlfd, curlsocktype purpose) const
 Describe the socket returned by HandleOpenSocket without issuing native descriptor queries.
MultiSocketDriver * multi_socket_driver ()
 Expose the callback state installed for the current socket-action drive.
std::size_t additional_handle_cleanup_count () const
void ResumeResponseIfRequested (CURL *easy)
 Resume receive-side callback output at one bounded drive boundary when the dedicated API plan requested it.
void ApplyPendingBackpressure ()
 Apply the BackpressureConfig cached by DriveScenario to the new connection_.

Static Protected Member Functions

static std::string_view FirstToken (std::string_view line)
 Remove optional leading horizontal whitespace and return the first token without allocating.
static std::string_view SecondToken (std::string_view line)
 Skip the first token and return the second whitespace-delimited token without allocating.
static bool TokenEquals (std::string_view token, std::string_view expected_uppercase)
 Fold only ASCII lowercase command letters.
Static Protected Member Functions inherited from proto_fuzzer::MockServerBase
static int WaitOnMultiFdset (CURLM *multi, CURLMcode *rc)
 Wait on curl's fdset with a short timeout.
static void ProbeMultiPollset (CURLM *multi)
 Ask curl to construct and inspect its connection-filter pollset without waiting.
static bool MultiPollsetWantsWrite (CURLM *multi, curl_socket_t socket)
 Inspect one socket's current writable interest through curl's public multi fdset API.
static bool UsesTimedDrive (const curl::fuzzer::proto::Scenario &scenario)
 Treat a non-default BackpressureConfig as an explicit request for the slower, timed drive policy.

Additional Inherited Members

Public Types inherited from proto_fuzzer::MockServerBase
using MultiObserver = std::function<void(CURLM*)>
 Callback type used to publish the driving multi handle to observers.
Protected Attributes inherited from proto_fuzzer::MockServerBase
std::unique_ptr< MockConnection > connection_
 The per-scenario MockConnection, lazily created by HandleOpenSocket().
int pending_recv_buf_bytes_
 Cached SO_RCVBUF/SO_SNDBUF setting in bytes.
std::size_t pending_drain_limit_
 Cached per-call DrainIncoming byte budget.
MultiSocketDriver * multi_socket_driver_
 Non-owning pointer into DriveScenario's stack.
std::size_t additional_handle_cleanup_count_
 Number of application-created handles, excluding the caller's parent, successfully removed from the current multi and cleaned up.
bool resume_response_
 True only for an API-plan multi drive with its one-shot write callback.
MultiObserver multi_observer_
 Observer receiving the live multi handle at the start of a drive.
Static Protected Attributes inherited from proto_fuzzer::MockServerBase
static constexpr int kMaxDriveIterations = 512
 Hard operation budget for one scenario.
static constexpr int kMaxIdleIterations = 8
 Consecutive no-progress budget for ordinary scenarios.
static constexpr int kMaxTimedIdleIterations = 256
 Explicit backpressure scenarios get a larger idle budget and may use the short timed wait above.

Detailed Description

Drives one control socketpair that speaks a line-oriented command/response protocol.

The base owns the transport lifecycle, the bounded perform loop, line buffering, the reply cursor, and the test-facing transcript. A concrete peer supplies HandleLine() and may switch the parser into body mode after a command that uploads data (SMTP DATA, IMAP APPEND). Replies are emitted exactly as scripted; a peer that needs protocol-specific rewriting, such as IMAP tag insertion, does so inside HandleLine().

Scenario.connection is a command-aligned script: initial_response is the server greeting and each on_readable entry answers the next command in order. Subclasses replace the transport through CreateConnection(); the implicit-TLS SMTPS peer uses that hook without touching the parser.

Definition at line 45 of file pingpong_mock_server.h.

Constructor & Destructor Documentation

◆ ~PingpongMockServer()

proto_fuzzer::PingpongMockServer::~PingpongMockServer ( )
overridedefault

Release the server-owned socketpair half after curl has returned its client descriptor.

The out-of-line destructor keeps MockConnection's complete type local to this translation unit.

◆ PingpongMockServer()

proto_fuzzer::PingpongMockServer::PingpongMockServer ( MultiDrivePolicy drive_policy = MultiDrivePolicy::kPerform)
explicitprotected

Construct the shared transport state without a borrowed protobuf or open socketpair.

RunLoop borrows a Scenario only for the synchronous DriveScenario call in which socket callbacks can run.

Parameters
drive_policyMulti-loop policy inherited from MockServerBase.

Definition at line 28 of file pingpong_mock_server.cc.

Member Function Documentation

◆ active_pollset_probe_count()

std::size_t proto_fuzzer::PingpongMockServer::active_pollset_probe_count ( ) const

Report how many requested zero-timeout multi-poll probes ran during the most recent drive.

RunLoop increments this only after a successful perform turn while curl still owns an active transfer and the control socket is open, making the count a focused test assertion rather than a syscall counter for default scenarios.

Returns
Number of active, connected pollset probes in the previous drive.

Definition at line 64 of file pingpong_mock_server.cc.

◆ BeginExactBody()

void proto_fuzzer::PingpongMockServer::BeginExactBody ( std::size_t length)
protected

Enter exact-length body mode.

Exactly length bytes are captured and no terminator is consumed, so the next byte after the body starts the next command. A zero length completes immediately.

Parameters
lengthAnnounced body byte count.

Definition at line 103 of file pingpong_mock_server.cc.

◆ BeginLiteralBody()

void proto_fuzzer::PingpongMockServer::BeginLiteralBody ( std::size_t length)
protected

Enter length-announced literal body mode.

Exactly length bytes are captured; the CRLF that follows the literal is consumed but not captured. A zero length is valid and waits directly for that terminator.

Parameters
lengthAnnounced literal byte count.

Definition at line 92 of file pingpong_mock_server.cc.

◆ BeginMarkerBody()

void proto_fuzzer::PingpongMockServer::BeginMarkerBody ( std::string_view terminator)
protected

Enter marker-terminated body mode.

The marker and any body bytes before it are captured together, matching SMTP's inclusion of its end-of-body CRLF.

Parameters
terminatorByte sequence that ends the body phase.

Definition at line 81 of file pingpong_mock_server.cc.

◆ BeginOpaqueDrain()

void proto_fuzzer::PingpongMockServer::BeginOpaqueDrain ( )
protected

Enter an opaque drain after a transport upgrade.

Every subsequent carrier byte is consumed without command parsing or test-facing capture.

Definition at line 112 of file pingpong_mock_server.cc.

◆ control_transcript()

const std::string & proto_fuzzer::PingpongMockServer::control_transcript ( ) const

Expose the bounded command capture from the most recent drive so tests can verify protocol states without coupling assertions to curl debug output.

Returns
A prefix of complete control commands, including line endings.

Definition at line 49 of file pingpong_mock_server.cc.

◆ CreateConnection()

std::unique_ptr< MockConnection > proto_fuzzer::PingpongMockServer::CreateConnection ( )
protectedvirtual

Create the default plaintext transport.

The SMTPS subclass overrides this factory while retaining the command/reply parser.

Returns
A new socketpair-backed connection.

Reimplemented in proto_fuzzer::DictMockServer, proto_fuzzer::ImapsMockServer, proto_fuzzer::Pop3sMockServer, proto_fuzzer::SmtpMockServer, and proto_fuzzer::SmtpsMockServer.

Definition at line 76 of file pingpong_mock_server.cc.

◆ FirstToken()

std::string_view proto_fuzzer::PingpongMockServer::FirstToken ( std::string_view line)
staticprotected

Remove optional leading horizontal whitespace and return the first token without allocating.

Protocol arguments are never interpreted here.

Parameters
lineComplete command line.
Returns
View of its first non-whitespace token.

Definition at line 247 of file pingpong_mock_server.cc.

◆ HandleBodyComplete()

virtual void proto_fuzzer::PingpongMockServer::HandleBodyComplete ( )
inlineprotectedvirtual

Called after a body phase reached its terminator and the parser returned to command mode.

The default does nothing.

Reimplemented in proto_fuzzer::RtspMockServer.

Definition at line 101 of file pingpong_mock_server.h.

◆ HandleDetachedMulti()

void proto_fuzzer::PingpongMockServer::HandleDetachedMulti ( CurlMultiPtr multi)
overrideprotectedvirtual

Give curl's graceful shutdown one last chance to emit its teardown command while the peer still owns its read half, then release the multi as the base class would.

The matching liveness reply was already queued by FinishConnections.

Parameters
multiDetached multi handle whose connection cache may be shutting the protocol connection down.

Reimplemented from proto_fuzzer::MockServerBase.

Definition at line 455 of file pingpong_mock_server.cc.

◆ HandleLine()

virtual void proto_fuzzer::PingpongMockServer::HandleLine ( std::string_view line)
protectedpure virtual

Answer one complete, newline-terminated command line.

Parameters
lineComplete command line, including its line ending.

Implemented in proto_fuzzer::DictMockServer, proto_fuzzer::ImapMockServer, proto_fuzzer::Pop3MockServer, proto_fuzzer::RtspMockServer, and proto_fuzzer::SmtpMockServer.

◆ HandleOpenSocket()

curl_socket_t proto_fuzzer::PingpongMockServer::HandleOpenSocket ( curlsocktype purpose = CURLSOCKTYPE_IPCXN,
struct curl_sockaddr * address = nullptr )
overrideprotectedvirtual

Create the single control socketpair and queue the server greeting.

These peers never open a second application socket, so any later request is rejected rather than silently replacing the live peer.

Parameters
purposeSocket role requested by curl.
addressUnused stream destination metadata required by the callback signature.
Returns
Client descriptor for the control channel, or CURL_SOCKET_BAD.

Implements proto_fuzzer::MockServerBase.

Reimplemented in proto_fuzzer::RtspMockServer.

Definition at line 138 of file pingpong_mock_server.cc.

◆ NextControlReply()

const std::string * proto_fuzzer::PingpongMockServer::NextControlReply ( )
protected

Return the next command-aligned response within the shared response-count budget.

Empty strings still advance the cursor: they are meaningful truncation mutations for ordinary command states.

Returns
Scenario-owned reply, or nullptr after the bounded prefix.

Definition at line 208 of file pingpong_mock_server.cc.

◆ ObserveIncomingData()

void proto_fuzzer::PingpongMockServer::ObserveIncomingData ( const unsigned char * data,
std::size_t size )
overrideprotectedvirtual

Append decoded application bytes to the pending parser buffer.

The outer service loop drains this buffer after every transport call, so it remains bounded by the scenario's command and upload budgets.

Parameters
dataFirst decoded byte.
sizeNumber of bytes available at data.

Implements proto_fuzzer::IncomingDataObserver.

Definition at line 124 of file pingpong_mock_server.cc.

◆ ResetProtocolState()

virtual void proto_fuzzer::PingpongMockServer::ResetProtocolState ( )
inlineprotectedvirtual

Reset protocol-specific parser state for a new drive.

The transport, cursors, transcript, upload capture, and body phase are already reset.

Reimplemented in proto_fuzzer::DictMockServer, proto_fuzzer::ImapMockServer, proto_fuzzer::RtspMockServer, and proto_fuzzer::SmtpMockServer.

Definition at line 109 of file pingpong_mock_server.h.

◆ RunLoop()

void proto_fuzzer::PingpongMockServer::RunLoop ( CURLM * multi,
CURL * easy,
const curl::fuzzer::proto::Scenario & scenario )
overrideprotectedvirtual

Alternate curl transitions with immediate peer service until the transfer completes or deterministic idle/operation caps win.

No select(), poll(), or sleep is needed: every transport is in-process, and malformed scripts are terminated by half-close after the bounded loop.

Parameters
multiMulti handle containing easy.
easyEasy handle already installed on this mock.
scenarioControl script to borrow.

Implements proto_fuzzer::MockServerBase.

Definition at line 467 of file pingpong_mock_server.cc.

◆ scenario()

const curl::fuzzer::proto::Scenario * proto_fuzzer::PingpongMockServer::scenario ( ) const
inlineprotected

Borrowed scenario for the synchronous drive, or nullptr outside RunLoop().

Returns
The Scenario borrowed by the active drive, or nullptr.

Definition at line 122 of file pingpong_mock_server.h.

◆ SecondToken()

std::string_view proto_fuzzer::PingpongMockServer::SecondToken ( std::string_view line)
staticprotected

Skip the first token and return the second whitespace-delimited token without allocating.

IMAP uses this to read the verb after the command tag.

Parameters
lineComplete command line.
Returns
View of its second whitespace-delimited token, or an empty view.

Definition at line 264 of file pingpong_mock_server.cc.

◆ ShutdownControlWrite()

void proto_fuzzer::PingpongMockServer::ShutdownControlWrite ( )
protected

Half-close the server-to-client direction while retaining the read half.

STARTTLS peers use this after their plaintext acceptance response so curl's newly installed TLS filter observes deterministic EOF instead of waiting.

Definition at line 237 of file pingpong_mock_server.cc.

◆ TokenEquals()

bool proto_fuzzer::PingpongMockServer::TokenEquals ( std::string_view token,
std::string_view expected_uppercase )
staticprotected

Fold only ASCII lowercase command letters.

Protocol verbs are ASCII tokens, so locale-aware case conversion would add state and undefined signed-char behavior without accepting anything curl can legitimately send.

Parameters
tokenParsed command token.
expected_uppercaseLiteral uppercase command name.
Returns
true when the tokens are equal ignoring ASCII case.

Definition at line 290 of file pingpong_mock_server.cc.

◆ uploaded_data()

const std::string & proto_fuzzer::PingpongMockServer::uploaded_data ( ) const

Expose a bounded prefix of bytes drained during the most recent body phase while continuing to drain every client byte, so test observability cannot create backpressure.

Returns
Body bytes curl sent, or an empty string when the peer has no upload direction.

Definition at line 56 of file pingpong_mock_server.cc.

◆ writable_pollset_probe_count()

std::size_t proto_fuzzer::PingpongMockServer::writable_pollset_probe_count ( ) const

Report how often curl retained writable interest while the peer held an incomplete control command.

Send-pressure tests use this conjunction to prove a protocol write remained pending rather than counting generic perform turns or transient writable states.

Returns
Writable pollset observations in the previous drive.

Definition at line 71 of file pingpong_mock_server.cc.

◆ WriteControlBytes()

bool proto_fuzzer::PingpongMockServer::WriteControlBytes ( std::string_view bytes)
protected

Keep failed peer writes local to the mock.

Response cursors must still advance after curl closes early, otherwise a replacement socket could see a reply intended for an earlier command.

Parameters
bytesResponse fragment to queue.
Returns
true when the complete fragment was queued.

Definition at line 220 of file pingpong_mock_server.cc.

◆ WriteNextReply()

bool proto_fuzzer::PingpongMockServer::WriteNextReply ( )
protected

Consume the next scripted reply.

Protocol peers use this when the reply that completes an upload must be queued at command-acceptance time because curl performs a blocking completion wait.

Returns
true when a scripted reply existed and was successfully written.

Definition at line 229 of file pingpong_mock_server.cc.


The documentation for this class was generated from the following files: