diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/test/fuzz/util.h | 41 | ||||
-rw-r--r-- | src/util/sock.cpp | 10 | ||||
-rw-r--r-- | src/util/sock.h | 17 |
3 files changed, 66 insertions, 2 deletions
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index db399abcf1..5294adf48e 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -685,6 +685,47 @@ public: return random_bytes.size(); } + int Connect(const sockaddr*, socklen_t) const override + { + // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted + // SetFuzzedErrNo() will always return the first element and we want to avoid Connect() + // returning -1 and setting errno to EAGAIN repeatedly. + constexpr std::array connect_errnos{ + ECONNREFUSED, + EAGAIN, + ECONNRESET, + EHOSTUNREACH, + EINPROGRESS, + EINTR, + ENETUNREACH, + ETIMEDOUT, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos); + return -1; + } + return 0; + } + + int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override + { + constexpr std::array getsockopt_errnos{ + ENOMEM, + ENOBUFS, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos); + return -1; + } + if (opt_val == nullptr) { + return 0; + } + std::memcpy(opt_val, + ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(), + *opt_len); + return 0; + } + bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override { return m_fuzzed_data_provider.ConsumeBool(); diff --git a/src/util/sock.cpp b/src/util/sock.cpp index f9ecfef5d4..0bc9795db3 100644 --- a/src/util/sock.cpp +++ b/src/util/sock.cpp @@ -66,6 +66,16 @@ ssize_t Sock::Recv(void* buf, size_t len, int flags) const return recv(m_socket, static_cast<char*>(buf), len, flags); } +int Sock::Connect(const sockaddr* addr, socklen_t addr_len) const +{ + return connect(m_socket, addr, addr_len); +} + +int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const +{ + return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len); +} + bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const { #ifdef USE_POLL diff --git a/src/util/sock.h b/src/util/sock.h index d923de531f..c4ad0cbc43 100644 --- a/src/util/sock.h +++ b/src/util/sock.h @@ -80,16 +80,29 @@ public: /** * send(2) wrapper. Equivalent to `send(this->Get(), data, len, flags);`. Code that uses this - * wrapper can be unit-tested if this method is overridden by a mock Sock implementation. + * wrapper can be unit tested if this method is overridden by a mock Sock implementation. */ virtual ssize_t Send(const void* data, size_t len, int flags) const; /** * recv(2) wrapper. Equivalent to `recv(this->Get(), buf, len, flags);`. Code that uses this - * wrapper can be unit-tested if this method is overridden by a mock Sock implementation. + * wrapper can be unit tested if this method is overridden by a mock Sock implementation. */ virtual ssize_t Recv(void* buf, size_t len, int flags) const; + /** + * connect(2) wrapper. Equivalent to `connect(this->Get(), addr, addrlen)`. Code that uses this + * wrapper can be unit tested if this method is overridden by a mock Sock implementation. + */ + virtual int Connect(const sockaddr* addr, socklen_t addr_len) const; + + /** + * getsockopt(2) wrapper. Equivalent to + * `getsockopt(this->Get(), level, opt_name, opt_val, opt_len)`. Code that uses this + * wrapper can be unit tested if this method is overridden by a mock Sock implementation. + */ + virtual int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const; + using Event = uint8_t; /** |