|
curl-fuzzer C++ reference
|
Abstract base for protocol-specific in-process mock servers. More...
#include <mock_server_base.h>
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. | |
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.
|
explicitprotected |
Construct an empty base instance with a fixed multi-drive policy.
| drive_policy | Whether to perform, use socket actions, or honor the containing Scenario's ApiPlan. |
Definition at line 69 of file mock_server_base.cc.
|
protected |
Definition at line 278 of file mock_server_base.cc.
|
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.
|
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.
| request_data | Callback 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.
| MockConnection * proto_fuzzer::MockServerBase::connection | ( | ) |
Definition at line 89 of file mock_server_base.cc.
|
virtual |
Establish a CONNECT_ONLY transport, then perform bounded direct I/O.
HTTP overrides this; other protocol mocks retain a safe fallback.
| easy | curl easy handle already Install()ed on this mock. |
| scenario | Scenario supplying response and direct-I/O bytes. |
Reimplemented in proto_fuzzer::MockServer.
Definition at line 259 of file mock_server_base.cc.
|
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.
| easy | curl easy handle already Install()ed on this mock. |
| scenario | Scenario whose response the mock must prepare. |
| use_events | Select curl's debug event-based easy entrypoint when the concrete mock supports it. |
Reimplemented in proto_fuzzer::MockServer.
Definition at line 249 of file mock_server_base.cc.
| 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.
| easy | curl easy handle already Install()ed on this mock. |
| scenario | the Scenario proto to drive. |
Definition at line 138 of file mock_server_base.cc.
|
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.
| curlfd | Descriptor returned by HandleOpenSocket. |
| purpose | Role curl assigned to the descriptor. |
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.
|
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.
| multi | Detached 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.
|
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.
| purpose | The role curl intends the new socket to serve. |
| address | Mutable destination and native socket description. |
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.
|
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.
| easy | The 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.
|
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.
Definition at line 272 of file mock_server_base.cc.
|
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.
| multi | Multi handle that owns the socket. |
| socket | Socket returned to curl by the open-socket callback. |
Definition at line 357 of file mock_server_base.cc.
|
virtual |
Default no-op for peers without protocol-specific observations.
Overrides retain bounded state only in coverage and introspector builds; a derived peer calls its base implementation before observing its own state.
Reimplemented in proto_fuzzer::DictMockServer, proto_fuzzer::FtpMockServer, proto_fuzzer::FtpsMockServer, proto_fuzzer::Http3MockServer, proto_fuzzer::HttpTransportMockServer, proto_fuzzer::ImapMockServer, proto_fuzzer::ImapsMockServer, proto_fuzzer::LdapMockServer, proto_fuzzer::LdapsMockServer, proto_fuzzer::MqttMockServer, proto_fuzzer::MqttsMockServer, proto_fuzzer::Pop3MockServer, proto_fuzzer::Pop3sMockServer, proto_fuzzer::ProxyOptionMockServer, proto_fuzzer::ProxyTransportMockServer, proto_fuzzer::RtspMockServer, proto_fuzzer::SmtpMockServer, proto_fuzzer::SmtpsMockServer, proto_fuzzer::TftpMockServer, proto_fuzzer::TlsWebSocketMockServer, and proto_fuzzer::WebSocketMockServer.
Definition at line 86 of file mock_server_base.cc.
|
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.
| multi | The active multi handle after at least one perform call. |
Definition at line 346 of file mock_server_base.cc.
|
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.
| easy | Active easy handle whose receive callbacks may be paused. |
Definition at line 285 of file mock_server_base.cc.
|
protectedpure virtual |
Subclass hook invoked from DriveScenario.
Runs the protocol-specific perform loop against a caller-owned multi that already has 'easy' added.
| multi | multi handle owned by DriveScenario; easy already added. |
| easy | the curl easy handle attached to the mock. |
| scenario | the 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.
|
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.
| observer | Callback receiving the live multi handle. |
Definition at line 95 of file mock_server_base.h.
|
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.
| scenario | Scenario whose backpressure settings select the policy. |
Definition at line 307 of file mock_server_base.cc.
|
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.
| multi | The multi handle whose fdset to poll. |
| rc | Out parameter: set to the CURLMcode on error. |
Definition at line 318 of file mock_server_base.cc.
|
friend |
C trampoline for CURLOPT_OPENSOCKETFUNCTION.
Declared at namespace scope so it can be a friend of MockServerBase.
| clientp | Pointer to the MockServerBase instance. |
| purpose | The socket role curl is asking the mock to provide. |
| address | Curl's mutable description of the intended destination. |
Definition at line 48 of file mock_server_base.cc.
|
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.
| clientp | Pointer to the MockServerBase instance. |
| curlfd | Descriptor returned by the open-socket callback. |
| purpose | Socket role assigned by curl. |
Definition at line 61 of file mock_server_base.cc.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.