| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/socket/fuzzed_socket.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/location.h" |
| 9 #include "base/logging.h" |
| 10 #include "base/thread_task_runner_handle.h" |
| 11 #include "net/base/io_buffer.h" |
| 12 |
| 13 namespace net { |
| 14 |
| 15 namespace { |
| 16 |
| 17 // Subset of the socket errors that can be returned by normal socket reads / |
| 18 // writes. The first one is returned when no more input data remains, so it's |
| 19 // one of the most common ones. |
| 20 const Error kReadWriteErrors[] = {ERR_CONNECTION_CLOSED, ERR_FAILED, |
| 21 ERR_TIMED_OUT, ERR_CONNECTION_RESET}; |
| 22 |
| 23 } // namespace |
| 24 |
| 25 FuzzedSocket::FuzzedSocket(const uint8_t* data, |
| 26 size_t data_size, |
| 27 const BoundNetLog& bound_net_log) |
| 28 : data_(reinterpret_cast<const char*>(data), data_size), |
| 29 bound_net_log_(bound_net_log), |
| 30 weak_factory_(this) {} |
| 31 |
| 32 FuzzedSocket::~FuzzedSocket() {} |
| 33 |
| 34 int FuzzedSocket::Read(IOBuffer* buf, |
| 35 int buf_len, |
| 36 const CompletionCallback& callback) { |
| 37 DCHECK(!read_pending_); |
| 38 |
| 39 bool sync; |
| 40 int result; |
| 41 |
| 42 if (net_error_ != OK) { |
| 43 // If an error has already been generated, use it to determine what to do. |
| 44 result = net_error_; |
| 45 sync = !error_pending_; |
| 46 } else { |
| 47 // Otherwise, use |data_|. |
| 48 uint8_t random_val = ConsumeUint8FromData(); |
| 49 sync = !!(random_val & 0x01); |
| 50 result = random_val >> 1; |
| 51 if (result > buf_len) |
| 52 result = buf_len; |
| 53 // Can't read more data than is available in |data_|. |
| 54 if (static_cast<size_t>(result) > data_.length()) |
| 55 result = data_.length(); |
| 56 |
| 57 if (result == 0) { |
| 58 net_error_ = ConsumeReadWriteErrorFromData(); |
| 59 result = net_error_; |
| 60 if (!sync) |
| 61 error_pending_ = true; |
| 62 } else { |
| 63 memcpy(buf->data(), data_.data(), result); |
| 64 data_ = data_.substr(result); |
| 65 } |
| 66 } |
| 67 |
| 68 // Graceful close of a socket returns OK, at least in theory. This doesn't |
| 69 // perfectly reflect real socket behavior, but close enough. |
| 70 if (result == ERR_CONNECTION_CLOSED) |
| 71 result = 0; |
| 72 |
| 73 if (sync) { |
| 74 if (result > 0) |
| 75 total_bytes_read_ += result; |
| 76 return result; |
| 77 } |
| 78 |
| 79 read_pending_ = true; |
| 80 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 81 FROM_HERE, base::Bind(&FuzzedSocket::OnReadComplete, |
| 82 weak_factory_.GetWeakPtr(), callback, result)); |
| 83 return ERR_IO_PENDING; |
| 84 } |
| 85 |
| 86 int FuzzedSocket::Write(IOBuffer* buf, |
| 87 int buf_len, |
| 88 const CompletionCallback& callback) { |
| 89 DCHECK(!write_pending_); |
| 90 |
| 91 bool sync; |
| 92 int result; |
| 93 |
| 94 if (net_error_ != OK) { |
| 95 // If an error has already been generated, use it to determine what to do. |
| 96 result = net_error_; |
| 97 sync = !error_pending_; |
| 98 } else { |
| 99 // Otherwise, use |data_|. |
| 100 uint8_t random_val = ConsumeUint8FromData(); |
| 101 sync = !!(random_val & 0x01); |
| 102 result = random_val >> 1; |
| 103 if (result > buf_len) |
| 104 result = buf_len; |
| 105 if (result == 0) { |
| 106 net_error_ = ConsumeReadWriteErrorFromData(); |
| 107 result = net_error_; |
| 108 if (!sync) |
| 109 error_pending_ = true; |
| 110 } |
| 111 } |
| 112 |
| 113 if (sync) { |
| 114 if (result > 0) |
| 115 total_bytes_written_ += result; |
| 116 return result; |
| 117 } |
| 118 |
| 119 write_pending_ = true; |
| 120 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 121 FROM_HERE, base::Bind(&FuzzedSocket::OnWriteComplete, |
| 122 weak_factory_.GetWeakPtr(), callback, result)); |
| 123 return ERR_IO_PENDING; |
| 124 } |
| 125 |
| 126 int FuzzedSocket::SetReceiveBufferSize(int32_t size) { |
| 127 return OK; |
| 128 } |
| 129 |
| 130 int FuzzedSocket::SetSendBufferSize(int32_t size) { |
| 131 return OK; |
| 132 } |
| 133 |
| 134 int FuzzedSocket::Connect(const CompletionCallback& callback) { |
| 135 // Sockets can normally be reused, but don't support it here. |
| 136 DCHECK_NE(net_error_, OK); |
| 137 DCHECK(!read_pending_); |
| 138 DCHECK(!write_pending_); |
| 139 DCHECK(!error_pending_); |
| 140 DCHECK(!total_bytes_read_); |
| 141 DCHECK(!total_bytes_written_); |
| 142 |
| 143 net_error_ = OK; |
| 144 return OK; |
| 145 } |
| 146 |
| 147 void FuzzedSocket::Disconnect() { |
| 148 net_error_ = ERR_CONNECTION_CLOSED; |
| 149 weak_factory_.InvalidateWeakPtrs(); |
| 150 read_pending_ = false; |
| 151 write_pending_ = false; |
| 152 error_pending_ = false; |
| 153 } |
| 154 |
| 155 bool FuzzedSocket::IsConnected() const { |
| 156 return net_error_ != OK && !error_pending_; |
| 157 } |
| 158 |
| 159 bool FuzzedSocket::IsConnectedAndIdle() const { |
| 160 return IsConnected(); |
| 161 } |
| 162 |
| 163 int FuzzedSocket::GetPeerAddress(IPEndPoint* address) const { |
| 164 if (!IsConnected()) |
| 165 return ERR_SOCKET_NOT_CONNECTED; |
| 166 *address = IPEndPoint(IPAddress(127, 0, 0, 1), 80); |
| 167 return OK; |
| 168 } |
| 169 |
| 170 int FuzzedSocket::GetLocalAddress(IPEndPoint* address) const { |
| 171 if (!IsConnected()) |
| 172 return ERR_SOCKET_NOT_CONNECTED; |
| 173 *address = IPEndPoint(IPAddress(127, 0, 0, 1), 43434); |
| 174 return OK; |
| 175 } |
| 176 |
| 177 const BoundNetLog& FuzzedSocket::NetLog() const { |
| 178 return bound_net_log_; |
| 179 } |
| 180 |
| 181 void FuzzedSocket::SetSubresourceSpeculation() {} |
| 182 |
| 183 void FuzzedSocket::SetOmniboxSpeculation() {} |
| 184 |
| 185 bool FuzzedSocket::WasEverUsed() const { |
| 186 return total_bytes_written_ != 0 || total_bytes_read_ != 0; |
| 187 } |
| 188 |
| 189 void FuzzedSocket::EnableTCPFastOpenIfSupported() {} |
| 190 |
| 191 bool FuzzedSocket::WasNpnNegotiated() const { |
| 192 return false; |
| 193 } |
| 194 |
| 195 NextProto FuzzedSocket::GetNegotiatedProtocol() const { |
| 196 return kProtoUnknown; |
| 197 } |
| 198 |
| 199 bool FuzzedSocket::GetSSLInfo(SSLInfo* ssl_info) { |
| 200 return false; |
| 201 } |
| 202 |
| 203 void FuzzedSocket::GetConnectionAttempts(ConnectionAttempts* out) const { |
| 204 out->clear(); |
| 205 } |
| 206 |
| 207 void FuzzedSocket::ClearConnectionAttempts() {} |
| 208 |
| 209 void FuzzedSocket::AddConnectionAttempts(const ConnectionAttempts& attempts) {} |
| 210 |
| 211 int64_t FuzzedSocket::GetTotalReceivedBytes() const { |
| 212 return total_bytes_read_; |
| 213 } |
| 214 |
| 215 uint8_t FuzzedSocket::ConsumeUint8FromData() { |
| 216 size_t length = data_.length(); |
| 217 if (!length) |
| 218 return 0; |
| 219 uint8_t out = data_[length - 1]; |
| 220 data_ = data_.substr(0, length - 1); |
| 221 return out; |
| 222 } |
| 223 |
| 224 Error FuzzedSocket::ConsumeReadWriteErrorFromData() { |
| 225 return kReadWriteErrors[ConsumeUint8FromData() % arraysize(kReadWriteErrors)]; |
| 226 } |
| 227 |
| 228 void FuzzedSocket::OnReadComplete(const CompletionCallback& callback, |
| 229 int result) { |
| 230 CHECK(read_pending_); |
| 231 read_pending_ = false; |
| 232 if (result <= 0) { |
| 233 error_pending_ = false; |
| 234 } else { |
| 235 total_bytes_read_ += result; |
| 236 } |
| 237 callback.Run(result); |
| 238 } |
| 239 |
| 240 void FuzzedSocket::OnWriteComplete(const CompletionCallback& callback, |
| 241 int result) { |
| 242 CHECK(write_pending_); |
| 243 write_pending_ = false; |
| 244 if (result <= 0) { |
| 245 error_pending_ = false; |
| 246 } else { |
| 247 total_bytes_written_ += result; |
| 248 } |
| 249 callback.Run(result); |
| 250 } |
| 251 |
| 252 } // namespace net |
| OLD | NEW |