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

Abstract base for protocol-specific in-process mock servers. More...

#include <mock_server_base.h>

Inheritance diagram for proto_fuzzer::MockServerBase:
proto_fuzzer::FtpMockServer proto_fuzzer::HappyEyeballsMockServer proto_fuzzer::Http3MockServer proto_fuzzer::LdapMockServer proto_fuzzer::MockServer proto_fuzzer::MqttMockServer proto_fuzzer::PingpongMockServer proto_fuzzer::TelnetMockServer proto_fuzzer::TftpMockServer proto_fuzzer::WebSocketMockServer

Public Types

using MultiObserver = std::function<void(CURLM*)>
 Callback type used to publish the driving multi handle to observers.

Public Member Functions

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

 MockServerBase (MultiDrivePolicy drive_policy=MultiDrivePolicy::kPerform)
 Construct an empty base instance with a fixed multi-drive policy.
virtual void HandleDetachedMulti (CurlMultiPtr multi)
 Dispose of or retain the multi after its easy handle has been removed.
virtual curl_socket_t HandleOpenSocket (curlsocktype purpose, struct curl_sockaddr *address)=0
 Subclass hook invoked by the OPENSOCKET trampoline.
virtual SocketSetupDisposition GetSocketSetupDisposition (curl_socket_t curlfd, curlsocktype purpose) const
 Describe the socket returned by HandleOpenSocket without issuing native descriptor queries.
virtual void RunLoop (CURLM *multi, CURL *easy, const curl::fuzzer::proto::Scenario &scenario)=0
 Subclass hook invoked from DriveScenario.
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 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.

Protected Attributes

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

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.

Friends

curl_socket_t MockServerBaseOpenSocketTrampoline (void *clientp, curlsocktype purpose, struct curl_sockaddr *address)
 C trampoline for CURLOPT_OPENSOCKETFUNCTION.
int MockServerBaseSockOptTrampoline (void *clientp, curl_socket_t curlfd, curlsocktype purpose)
 Translate explicit peer transport metadata into curl's sockopt callback contract.

Detailed Description

Abstract base for protocol-specific in-process mock servers.

Owns a single MockConnection (the socketpair curl talks to) and dispatches the OPENSOCKET callback through a virtual HandleOpenSocket so the subclass can decide whether to write anything immediately. Each subclass overrides RunLoop to seed itself from the Scenario proto and run its own perform loop; the base's DriveScenario owns the curl_multi handle around that call.

Definition at line 67 of file mock_server_base.h.

Constructor & Destructor Documentation

◆ MockServerBase()

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

Construct an empty base instance with a fixed multi-drive policy.

Parameters
drive_policyWhether to perform, use socket actions, or honor the containing Scenario's ApiPlan.

Definition at line 69 of file mock_server_base.cc.

Member Function Documentation

◆ additional_handle_cleanup_count()

std::size_t proto_fuzzer::MockServerBase::additional_handle_cleanup_count ( ) const
protected
Returns
extra easy handles removed and cleaned after the latest drive. Server push is currently the only path that can add one behind the caller's back; exposing the count to subclasses keeps ownership in this multi-owning base while allowing focused lifecycle assertions.

Definition at line 278 of file mock_server_base.cc.

◆ ApplyPendingBackpressure()

void proto_fuzzer::MockServerBase::ApplyPendingBackpressure ( )
protected

Apply the BackpressureConfig cached by DriveScenario to the new connection_.

Subclasses call this at the end of HandleOpenSocket, before returning the client fd, so SO_RCVBUF takes effect before traffic flows. Safe to call when connection_ is null or both knobs are zero: those cases are no-ops.

Definition at line 296 of file mock_server_base.cc.

◆ ConfigureRequestData()

void proto_fuzzer::MockServerBase::ConfigureRequestData ( ScenarioRequestData * request_data)
virtual

Bind protocol-specific work to the request-data callbacks after their per-scenario state has been constructed.

Ordinary HTTP and WebSocket mocks regain control in their outer perform loops and drain client traffic there. Most mocks therefore need no hook; TELNET uses this upload-callback boundary to drain client replies while curl owns the thread.

Parameters
request_dataCallback state that outlives the subsequent drive.

Reimplemented in proto_fuzzer::DohHttpsRrMockServer, proto_fuzzer::HappyEyeballsMockServer, and proto_fuzzer::TelnetMockServer.

Definition at line 125 of file mock_server_base.cc.

◆ connection()

MockConnection * proto_fuzzer::MockServerBase::connection ( )
Returns
the owned MockConnection, or nullptr if one has not been opened.

Definition at line 89 of file mock_server_base.cc.

◆ DriveConnectOnlyScenario()

ConnectOnlyRunStats proto_fuzzer::MockServerBase::DriveConnectOnlyScenario ( CURL * easy,
const curl::fuzzer::proto::Scenario & scenario )
virtual

Establish a CONNECT_ONLY transport, then perform bounded direct I/O.

HTTP overrides this; other protocol mocks retain a safe fallback.

Parameters
easycurl easy handle already Install()ed on this mock.
scenarioScenario supplying response and direct-I/O bytes.
Returns
Results and byte counts from connect, send, and receive probes.

Reimplemented in proto_fuzzer::MockServer.

Definition at line 259 of file mock_server_base.cc.

◆ DriveEasyScenario()

CURLcode proto_fuzzer::MockServerBase::DriveEasyScenario ( CURL * easy,
const curl::fuzzer::proto::Scenario & scenario,
bool use_events = false )
virtual

Run through the public easy entrypoint when a protocol mock can preload all peer work before curl takes control.

The base preserves the ordinary multi-drive fallback for protocols that require an outer driver to make progress. The API policy currently forces HTTP, whose override preloads its bounded response and calls curl_easy_perform without a thread.

Parameters
easycurl easy handle already Install()ed on this mock.
scenarioScenario whose response the mock must prepare.
use_eventsSelect curl's debug event-based easy entrypoint when the concrete mock supports it.
Returns
Transfer result reported by the selected easy or fallback drive.

Reimplemented in proto_fuzzer::MockServer.

Definition at line 249 of file mock_server_base.cc.

◆ DriveScenario()

CURLcode proto_fuzzer::MockServerBase::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.

Read the result before removing the only easy handle so every protocol runner exercises the public multi-result path. Harness setup failures return a stable sentinel; fuzzer callers may ignore it while unit tests can assert the protocol result without adding another callback or global.

Parameters
easycurl easy handle already Install()ed on this mock.
scenariothe Scenario proto to drive.
Returns
the completed transfer's CURLcode, or CURLE_FAILED_INIT when the bounded drive could not produce a completion message.

Definition at line 138 of file mock_server_base.cc.

◆ GetSocketSetupDisposition()

SocketSetupDisposition proto_fuzzer::MockServerBase::GetSocketSetupDisposition ( curl_socket_t curlfd,
curlsocktype purpose ) const
protectedvirtual

Describe the socket returned by HandleOpenSocket without issuing native descriptor queries.

Stream peers return connected socketpairs; accepted sockets and datagram peers require curl's ordinary setup.

Parameters
curlfdDescriptor returned by HandleOpenSocket.
purposeRole curl assigned to the descriptor.
Returns
Whether curl must perform its normal socket setup.

Reimplemented in proto_fuzzer::FtpMockServer, proto_fuzzer::HappyEyeballsMockServer, proto_fuzzer::Http3MockServer, and proto_fuzzer::TftpMockServer.

Definition at line 110 of file mock_server_base.cc.

◆ HandleDetachedMulti()

void proto_fuzzer::MockServerBase::HandleDetachedMulti ( CurlMultiPtr multi)
protectedvirtual

Dispose of or retain the multi after its easy handle has been removed.

The default destroys it before DriveScenario returns. A protocol mock may retain it as member state when its fixed lifecycle requires easy cleanup to happen first.

Parameters
multiDetached multi handle and its live connection cache.

Reimplemented in proto_fuzzer::H2CleartextMockServer, proto_fuzzer::H2OriginMockServer, and proto_fuzzer::PingpongMockServer.

Definition at line 237 of file mock_server_base.cc.

◆ HandleOpenSocket()

virtual curl_socket_t proto_fuzzer::MockServerBase::HandleOpenSocket ( curlsocktype purpose,
struct curl_sockaddr * address )
protectedpure virtual

Subclass hook invoked by the OPENSOCKET trampoline.

The subclass owns the decision to construct connection_, push any initial bytes, and hand the client fd back to libcurl. Passing curl's mutable destination through is essential for datagram protocols: TFTP must replace the nominal URL port with its per-scenario loopback request socket before curl records the address used by sendto(). Stream socketpair peers simply ignore it.

Parameters
purposeThe role curl intends the new socket to serve.
addressMutable destination and native socket description.
Returns
the client-side fd to hand to libcurl, or CURL_SOCKET_BAD.

Implemented in proto_fuzzer::FtpMockServer, proto_fuzzer::HappyEyeballsMockServer, proto_fuzzer::Http3MockServer, proto_fuzzer::LdapMockServer, proto_fuzzer::MockServer, proto_fuzzer::MqttMockServer, proto_fuzzer::PingpongMockServer, proto_fuzzer::RtspMockServer, proto_fuzzer::TelnetMockServer, proto_fuzzer::TftpMockServer, and proto_fuzzer::WebSocketMockServer.

◆ Install()

void proto_fuzzer::MockServerBase::Install ( CURL * easy)
virtual

Install the common OPENSOCKETFUNCTION / OPENSOCKETDATA / SOCKOPTFUNCTION callbacks on 'easy'.

All subclasses share the trampolines, which route back into this instance through HandleOpenSocket. Subclasses may override to layer additional protocol-specific setopts, such as a WRITEFUNCTION that exercises protocol APIs from inside a curl callback.

Parameters
easyThe curl easy handle to configure.

Reimplemented in proto_fuzzer::ConnectUdpProxyMockServer, proto_fuzzer::DictMockServer, proto_fuzzer::DohHttpsRrMockServer, proto_fuzzer::FtpsMockServer, proto_fuzzer::H2CleartextMockServer, proto_fuzzer::H2OriginMockServer, proto_fuzzer::H2ProxyMockServer, proto_fuzzer::HappyEyeballsMockServer, proto_fuzzer::Http3MockServer, proto_fuzzer::HttpTransportMockServer, proto_fuzzer::ImapsMockServer, proto_fuzzer::InterfaceOptionMockServer, proto_fuzzer::LdapsMockServer, proto_fuzzer::MqttsMockServer, proto_fuzzer::Pop3sMockServer, proto_fuzzer::ProxyOptionMockServer, proto_fuzzer::ProxyTransportMockServer, proto_fuzzer::SmtpsMockServer, proto_fuzzer::TlsMockServer, proto_fuzzer::TlsWebSocketMockServer, and proto_fuzzer::WebSocketMockServer.

Definition at line 97 of file mock_server_base.cc.

◆ multi_socket_driver()

MultiSocketDriver * proto_fuzzer::MockServerBase::multi_socket_driver ( )
protected

Expose the callback state installed for the current socket-action drive.

HTTP's RunLoop uses this instead of reading the proto directly, so only the dedicated API binary can opt into lifecycle work and compatibility inputs containing the new field retain their old behavior. Ownership remains in DriveScenario so no subclass can shorten the driver's lifetime.

Returns
active driver, or nullptr for the ordinary perform path.

Definition at line 272 of file mock_server_base.cc.

◆ MultiPollsetWantsWrite()

bool proto_fuzzer::MockServerBase::MultiPollsetWantsWrite ( CURLM * multi,
curl_socket_t socket )
staticprotected

Inspect one socket's current writable interest through curl's public multi fdset API.

MockConnection already rejects descriptors outside FD_SETSIZE, so the matching FD_ISSET operation remains bounded.

Parameters
multiMulti handle that owns the socket.
socketSocket returned to curl by the open-socket callback.
Returns
true when curl currently waits for the socket to become writable.

Definition at line 357 of file mock_server_base.cc.

◆ ObserveState()

◆ ProbeMultiPollset()

void proto_fuzzer::MockServerBase::ProbeMultiPollset ( CURLM * multi)
staticprotected

Ask curl to construct and inspect its connection-filter pollset without waiting.

A perform-only harness can complete local socketpair transfers while skipping the public multi-poll path used by event-driven applications. Selected opt-in scenarios make zero-timeout probes to retain that coverage without taxing the default fast path. The result is ignored: the protocol-specific perform loop determines transfer progress.

Parameters
multiThe active multi handle after at least one perform call.

Definition at line 346 of file mock_server_base.cc.

◆ ResumeResponseIfRequested()

void proto_fuzzer::MockServerBase::ResumeResponseIfRequested ( CURL * easy)
protected

Resume receive-side callback output at one bounded drive boundary when the dedicated API plan requested it.

Calling CONT before the callback pauses is harmless; repeating it ensures a later response chunk cannot leave the transfer suspended until timeout.

Parameters
easyActive easy handle whose receive callbacks may be paused.

Definition at line 285 of file mock_server_base.cc.

◆ RunLoop()

virtual void proto_fuzzer::MockServerBase::RunLoop ( CURLM * multi,
CURL * easy,
const curl::fuzzer::proto::Scenario & scenario )
protectedpure virtual

Subclass hook invoked from DriveScenario.

Runs the protocol-specific perform loop against a caller-owned multi that already has 'easy' added.

Parameters
multimulti handle owned by DriveScenario; easy already added.
easythe curl easy handle attached to the mock.
scenariothe Scenario proto to drive.

Implemented in proto_fuzzer::DictMockServer, proto_fuzzer::DohHttpsRrMockServer, proto_fuzzer::FtpMockServer, proto_fuzzer::GopherMockServer, proto_fuzzer::H2CleartextMockServer, proto_fuzzer::H2OriginMockServer, proto_fuzzer::HappyEyeballsMockServer, proto_fuzzer::Http3MockServer, proto_fuzzer::LdapMockServer, proto_fuzzer::MockServer, proto_fuzzer::MqttMockServer, proto_fuzzer::PingpongMockServer, proto_fuzzer::ProxyOptionMockServer, proto_fuzzer::TelnetMockServer, proto_fuzzer::TftpMockServer, and proto_fuzzer::WebSocketMockServer.

◆ SetMultiObserver()

void proto_fuzzer::MockServerBase::SetMultiObserver ( MultiObserver observer)
inline

Register an observer invoked with the live multi handle after 'easy' is attached and before the drive loop starts.

The API lifecycle lane uses it so public API probes fired from inside callbacks can target the multi that actually owns the transfer. Passing an empty observer clears it.

Parameters
observerCallback receiving the live multi handle.

Definition at line 95 of file mock_server_base.h.

◆ UsesTimedDrive()

bool proto_fuzzer::MockServerBase::UsesTimedDrive ( const curl::fuzzer::proto::Scenario & scenario)
staticprotected

Treat a non-default BackpressureConfig as an explicit request for the slower, timed drive policy.

Proto3 scalar defaults make this deterministic: a present-but-empty message remains on the ordinary fast path.

Parameters
scenarioScenario whose backpressure settings select the policy.
Returns
true when the scenario explicitly opted into socket backpressure.

Definition at line 307 of file mock_server_base.cc.

◆ WaitOnMultiFdset()

int proto_fuzzer::MockServerBase::WaitOnMultiFdset ( CURLM * multi,
CURLMcode * rc )
staticprotected

Wait on curl's fdset with a short timeout.

Drive loops call this only for scenarios that explicitly request backpressure/timing behaviour; ordinary scenarios run without wall-clock sleeps.

Parameters
multiThe multi handle whose fdset to poll.
rcOut parameter: set to the CURLMcode on error.
Returns
select()'s result, or -1 on curl_multi_fdset failure.

Definition at line 318 of file mock_server_base.cc.

◆ MockServerBaseOpenSocketTrampoline

curl_socket_t MockServerBaseOpenSocketTrampoline ( void * clientp,
curlsocktype purpose,
struct curl_sockaddr * address )
friend

C trampoline for CURLOPT_OPENSOCKETFUNCTION.

Declared at namespace scope so it can be a friend of MockServerBase.

Parameters
clientpPointer to the MockServerBase instance.
purposeThe socket role curl is asking the mock to provide.
addressCurl's mutable description of the intended destination.
Returns
The client-side socket fd as a curl_socket_t.

Definition at line 48 of file mock_server_base.cc.

◆ MockServerBaseSockOptTrampoline

int MockServerBaseSockOptTrampoline ( void * clientp,
curl_socket_t curlfd,
curlsocktype purpose )
friend

Translate explicit peer transport metadata into curl's sockopt callback contract.

The descriptor is used only as an opaque identity; sandbox policy must not decide whether an otherwise valid in-process transport can run.

Parameters
clientpPointer to the MockServerBase instance.
curlfdDescriptor returned by the open-socket callback.
purposeSocket role assigned by curl.
Returns
CURL_SOCKOPT_ALREADY_CONNECTED for prepared stream peers, otherwise CURL_SOCKOPT_OK.

Definition at line 61 of file mock_server_base.cc.

Member Data Documentation

◆ connection_

std::unique_ptr<MockConnection> proto_fuzzer::MockServerBase::connection_
protected

The per-scenario MockConnection, lazily created by HandleOpenSocket().

Subclasses read/write through this pointer inside their RunLoop.

Definition at line 158 of file mock_server_base.h.

◆ kMaxDriveIterations

int proto_fuzzer::MockServerBase::kMaxDriveIterations = 512
staticconstexprprotected

Hard operation budget for one scenario.

This bounds cases that continue making tiny amounts of progress (for example a one-byte backpressure drain) without relying on wall-clock time.

Definition at line 140 of file mock_server_base.h.

◆ kMaxIdleIterations

int proto_fuzzer::MockServerBase::kMaxIdleIterations = 8
staticconstexprprotected

Consecutive no-progress budget for ordinary scenarios.

Socketpair I/O is local and should settle immediately, so a handful of extra performs is enough to flush curl's state machine without sleeping.

Definition at line 145 of file mock_server_base.h.

◆ kMaxTimedIdleIterations

int proto_fuzzer::MockServerBase::kMaxTimedIdleIterations = 256
staticconstexprprotected

Explicit backpressure scenarios get a larger idle budget and may use the short timed wait above.

This keeps timeout/error branches reachable while ensuring ordinary mutations never inherit their cost.

Definition at line 150 of file mock_server_base.h.

◆ multi_socket_driver_

MultiSocketDriver* proto_fuzzer::MockServerBase::multi_socket_driver_
protected

Non-owning pointer into DriveScenario's stack.

That scope encloses easy removal and multi cleanup, the complete interval in which callbacks may still fire.

Definition at line 171 of file mock_server_base.h.

◆ pending_drain_limit_

std::size_t proto_fuzzer::MockServerBase::pending_drain_limit_
protected

Cached per-call DrainIncoming byte budget.

Same population timing as pending_recv_buf_bytes_; 0 means unlimited (legacy drain behaviour).

Definition at line 166 of file mock_server_base.h.

◆ pending_recv_buf_bytes_

int proto_fuzzer::MockServerBase::pending_recv_buf_bytes_
protected

Cached SO_RCVBUF/SO_SNDBUF setting in bytes.

Populated by DriveScenario before the first curl_multi_perform so HandleOpenSocket can consult it when it constructs the MockConnection.

Definition at line 163 of file mock_server_base.h.


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