22namespace proto_fuzzer {
29constexpr std::size_t kMinClientSendBufferBytes = 64 * 1024;
36constexpr std::size_t kCurlTelnetSuboptionReplyBytes = 2048;
37constexpr std::size_t kSmallNegotiationHeadroomBytes = 4 * 1024;
38constexpr std::size_t kMaxBufferedClientBytes =
41static_assert(kMaxBufferedClientBytes <= kMinClientSendBufferBytes,
42 "TELNET mutation caps exceed the verified client send buffer");
48void CopyTelnetResponsePrefix(
const curl::fuzzer::proto::Connection& source,
49 curl::fuzzer::proto::Connection* destination) {
51 const auto copy_fragment = [&bytes_left](
const std::string& fragment, std::string* output) {
52 const std::size_t retained = std::min(fragment.size(), bytes_left);
53 output->assign(fragment.data(), retained);
54 bytes_left -= retained;
55 return retained == fragment.size();
58 if (!copy_fragment(source.initial_response(), destination->mutable_initial_response())) {
62 const std::size_t chunk_count =
64 for (std::size_t index = 0; index < chunk_count && bytes_left != 0; ++index) {
65 if (!copy_fragment(source.on_readable(
static_cast<int>(index)), destination->add_on_readable())) {
86 if (request_data !=
nullptr) {
92void TelnetMockServer::DrainBeforeUploadRead(
void* userdata) {
94 if (server !=
nullptr && server->connection_) {
95 (void)server->connection_->DrainIncoming();
114 if (scenario_ ==
nullptr || socket_opened_) {
115 return CURL_SOCKET_BAD;
117 socket_opened_ =
true;
122 return CURL_SOCKET_BAD;
125 if (!
connection_->EnsureClientSendBufferSize(kMinClientSendBufferBytes)) {
127 return CURL_SOCKET_BAD;
130 const auto write_bytes = [
this](
const std::string& bytes) {
131 return bytes.empty() ||
connection_->WriteAll(
reinterpret_cast<const unsigned char*
>(bytes.data()), bytes.size());
137 const auto& source = scenario_->connection();
138 curl::fuzzer::proto::Connection script;
139 CopyTelnetResponsePrefix(source, &script);
141 bool complete = write_bytes(script.initial_response());
142 const std::size_t chunk_count =
static_cast<std::size_t
>(script.on_readable_size());
143 for (std::size_t index = 0; complete && index < chunk_count; ++index) {
144 complete = write_bytes(script.on_readable(
static_cast<int>(index)));
164 scenario_ = &scenario;
165 socket_opened_ =
false;
168 int still_running = 1;
169 for (
int iteration = 0; still_running && iteration <
kMaxIdleIterations; ++iteration) {
170 const CURLMcode result = curl_multi_perform(multi, &still_running);
171 if (result != CURLM_OK) {
std::unique_ptr< MockConnection > connection_
The per-scenario MockConnection, lazily created by HandleOpenSocket().
static constexpr int kMaxIdleIterations
Consecutive no-progress budget for ordinary scenarios.
Builds HTTP headers or TELNET options, MIME state, and upload callbacks whose storage or userdata lib...
void SetBeforeUploadReadCallback(UploadScriptState::BeforeReadCallback callback, void *userdata)
Arrange protocol-specific work immediately before every upload read.
Preloads a complete bounded TELNET response before curl enters its protocol loop.
curl_socket_t HandleOpenSocket(curlsocktype purpose=CURLSOCKTYPE_IPCXN, struct curl_sockaddr *address=nullptr) override
Create one socketpair, preload every raw response fragment curl can observe, then half-close the peer...
void ConfigureRequestData(ScenarioRequestData *request_data) override
Attach the synchronous peer drain to TELNET's upload callback.
void RunLoop(CURLM *multi, CURL *easy, const curl::fuzzer::proto::Scenario &scenario) override
Drive a small number of non-waiting multi transitions.
TelnetMockServer()
Start without a borrowed scenario.
~TelnetMockServer() override
The base owns and closes the server half after curl releases its client fd.
MockConnection and MockServer — the in-process peer that feeds canned response bytes to libcurl over ...
Owns pointer-valued HTTP headers, TELNET options, MIME state, and upload callback state derived from ...
Shared complexity limits for structured scenarios.
constexpr std::size_t kMaxTelnetControlBytes
Bound reply amplification as well as input bytes.
constexpr std::size_t kMaxTelnetResponseBytes
TELNET consumes the peer synchronously, so only this bounded prefix can be preloaded before curl ente...
constexpr std::size_t kMaxTelnetUploadBytes
TELNET writes upload bytes while its blocking driver owns the thread, so keep total callback work sma...
constexpr std::size_t kMaxTelnetResponseChunks
Raw fragments are all preloaded before TELNET starts.
Non-blocking in-process peer for curl's blocking TELNET driver.
void BoundTelnetResponse(curl::fuzzer::proto::Connection *connection)
Retain the response prefix that TelnetMockServer can preload safely.
Shared TELNET response normalization.