| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/socket/fuzzed_datagram_client_socket.h" |
| |
| #include <algorithm> |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/strings/string_piece.h" |
| #include "base/test/fuzzed_data_provider.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/ip_address.h" |
| #include "net/base/net_errors.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| |
| namespace net { |
| |
| // Subset of network errors that can occur on each operation. Less clear cut |
| // than TCP errors, so some of these may not actually be possible. |
| const Error kConnectErrors[] = {ERR_FAILED, ERR_ADDRESS_UNREACHABLE, |
| ERR_ACCESS_DENIED}; |
| const Error kReadErrors[] = {ERR_FAILED, ERR_ADDRESS_UNREACHABLE}; |
| const Error kWriteErrors[] = {ERR_FAILED, ERR_ADDRESS_UNREACHABLE, |
| ERR_MSG_TOO_BIG}; |
| |
| FuzzedDatagramClientSocket::FuzzedDatagramClientSocket( |
| base::FuzzedDataProvider* data_provider) |
| : data_provider_(data_provider), weak_factory_(this) {} |
| |
| FuzzedDatagramClientSocket::~FuzzedDatagramClientSocket() = default; |
| |
| int FuzzedDatagramClientSocket::Connect(const IPEndPoint& address) { |
| CHECK(!connected_); |
| |
| // Decide if the connect attempt succeeds. |
| if (data_provider_->ConsumeBool()) { |
| connected_ = true; |
| remote_address_ = address; |
| return OK; |
| } |
| |
| // On failure, return a random connect error. |
| return data_provider_->PickValueInArray(kConnectErrors); |
| } |
| |
| int FuzzedDatagramClientSocket::ConnectUsingNetwork( |
| NetworkChangeNotifier::NetworkHandle network, |
| const IPEndPoint& address) { |
| CHECK(!connected_); |
| return ERR_NOT_IMPLEMENTED; |
| } |
| |
| int FuzzedDatagramClientSocket::FuzzedDatagramClientSocket:: |
| ConnectUsingDefaultNetwork(const IPEndPoint& address) { |
| CHECK(!connected_); |
| return ERR_NOT_IMPLEMENTED; |
| } |
| |
| NetworkChangeNotifier::NetworkHandle |
| FuzzedDatagramClientSocket::GetBoundNetwork() const { |
| return NetworkChangeNotifier::kInvalidNetworkHandle; |
| } |
| |
| void FuzzedDatagramClientSocket::ApplySocketTag(const SocketTag& tag) {} |
| |
| void FuzzedDatagramClientSocket::Close() { |
| connected_ = false; |
| read_pending_ = false; |
| write_pending_ = false; |
| remote_address_ = IPEndPoint(); |
| weak_factory_.InvalidateWeakPtrs(); |
| } |
| |
| int FuzzedDatagramClientSocket::GetPeerAddress(IPEndPoint* address) const { |
| if (!connected_) |
| return ERR_SOCKET_NOT_CONNECTED; |
| *address = remote_address_; |
| return OK; |
| } |
| |
| int FuzzedDatagramClientSocket::GetLocalAddress(IPEndPoint* address) const { |
| if (!connected_) |
| return ERR_SOCKET_NOT_CONNECTED; |
| *address = IPEndPoint(IPAddress(1, 2, 3, 4), 43210); |
| return OK; |
| } |
| |
| void FuzzedDatagramClientSocket::UseNonBlockingIO() {} |
| |
| int FuzzedDatagramClientSocket::WriteAsync( |
| DatagramBuffers buffers, |
| CompletionOnceCallback callback, |
| const NetworkTrafficAnnotationTag& traffic_annotation) { |
| return -1; |
| } |
| |
| int FuzzedDatagramClientSocket::WriteAsync( |
| const char* buffer, |
| size_t buf_len, |
| CompletionOnceCallback callback, |
| const NetworkTrafficAnnotationTag& traffic_annotation) { |
| return -1; |
| } |
| |
| DatagramBuffers FuzzedDatagramClientSocket::GetUnwrittenBuffers() { |
| DatagramBuffers result; |
| return result; |
| } |
| |
| void FuzzedDatagramClientSocket::SetWriteAsyncEnabled(bool enabled) {} |
| bool FuzzedDatagramClientSocket::WriteAsyncEnabled() { |
| return false; |
| } |
| void FuzzedDatagramClientSocket::SetMaxPacketSize(size_t max_packet_size) {} |
| void FuzzedDatagramClientSocket::SetWriteMultiCoreEnabled(bool enabled) {} |
| void FuzzedDatagramClientSocket::SetSendmmsgEnabled(bool enabled) {} |
| void FuzzedDatagramClientSocket::SetWriteBatchingActive(bool active) {} |
| |
| const NetLogWithSource& FuzzedDatagramClientSocket::NetLog() const { |
| return net_log_; |
| } |
| |
| int FuzzedDatagramClientSocket::Read(IOBuffer* buf, |
| int buf_len, |
| CompletionOnceCallback callback) { |
| CHECK(!callback.is_null()); |
| CHECK_GT(buf_len, 0); |
| CHECK(!read_pending_); |
| |
| // Normally calling this on disconnected sockets is allowed, but code really |
| // shouldn't be doing this. If it is, it's best to figure out why, and fix |
| // it. Note that |connected_| is only set to false on calls to Close(), not on |
| // errors. |
| CHECK(connected_); |
| |
| // Get contents of response. |
| std::string data(data_provider_->ConsumeBytes( |
| data_provider_->ConsumeUint32InRange(0, buf_len))); |
| |
| int result; |
| if (data.size() > 0) { |
| // If the response is not empty, consider it a successful read. |
| result = data.size(); |
| std::copy(data.begin(), data.end(), buf->data()); |
| } else { |
| // If the response is empty, pick a random read error. |
| result = data_provider_->PickValueInArray(kReadErrors); |
| } |
| |
| // Decide if result should be returned synchronously. |
| if (data_provider_->ConsumeBool()) |
| return result; |
| |
| read_pending_ = true; |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&FuzzedDatagramClientSocket::OnReadComplete, |
| weak_factory_.GetWeakPtr(), std::move(callback), result)); |
| return ERR_IO_PENDING; |
| } |
| |
| int FuzzedDatagramClientSocket::Write( |
| IOBuffer* buf, |
| int buf_len, |
| CompletionOnceCallback callback, |
| const NetworkTrafficAnnotationTag& /* traffic_annotation */) { |
| CHECK(!callback.is_null()); |
| CHECK(!write_pending_); |
| |
| // Normally this is allowed, but code really shouldn't be doing this - if it |
| // is, it's best to figure out why, and fix it. |
| CHECK(connected_); |
| |
| int result; |
| // Decide if success or failure. |
| if (data_provider_->ConsumeBool()) { |
| // On success, everything is written. |
| result = buf_len; |
| } else { |
| // On failure, pick a random write error. |
| result = data_provider_->PickValueInArray(kWriteErrors); |
| } |
| |
| // Decide if result should be returned synchronously. |
| if (data_provider_->ConsumeBool()) |
| return result; |
| |
| write_pending_ = true; |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&FuzzedDatagramClientSocket::OnWriteComplete, |
| weak_factory_.GetWeakPtr(), std::move(callback), result)); |
| return ERR_IO_PENDING; |
| } |
| |
| int FuzzedDatagramClientSocket::SetReceiveBufferSize(int32_t size) { |
| return OK; |
| } |
| |
| int FuzzedDatagramClientSocket::SetSendBufferSize(int32_t size) { |
| return OK; |
| } |
| |
| int FuzzedDatagramClientSocket::SetDoNotFragment() { |
| return OK; |
| } |
| |
| void FuzzedDatagramClientSocket::OnReadComplete( |
| net::CompletionOnceCallback callback, |
| int result) { |
| CHECK(connected_); |
| CHECK(read_pending_); |
| |
| read_pending_ = false; |
| std::move(callback).Run(result); |
| } |
| |
| void FuzzedDatagramClientSocket::OnWriteComplete( |
| net::CompletionOnceCallback callback, |
| int result) { |
| CHECK(connected_); |
| CHECK(write_pending_); |
| |
| write_pending_ = false; |
| std::move(callback).Run(result); |
| } |
| |
| } // namespace net |