blob: 9eced0d0cfa6cb5d97becfe17159766435977295 [file] [log] [blame]
// Copyright (c) 2011 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/curvecp/test_client.h"
#include <string>
#include <deque>
#include <vector>
#include "base/logging.h"
#include "base/message_loop.h"
#include "net/base/address_list.h"
#include "net/base/host_resolver.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/single_request_host_resolver.h"
#include "net/curvecp/curvecp_client_socket.h"
namespace net {
TestClient::TestClient()
: socket_(NULL),
errors_(0),
bytes_to_send_(0),
ALLOW_THIS_IN_INITIALIZER_LIST(
connect_callback_(this, &TestClient::OnConnectComplete)),
ALLOW_THIS_IN_INITIALIZER_LIST(
read_callback_(this, &TestClient::OnReadComplete)),
ALLOW_THIS_IN_INITIALIZER_LIST(
write_callback_(this, &TestClient::OnWriteComplete)),
finished_callback_(NULL) {
}
TestClient::~TestClient() {
if (socket_) {
// TODO(mbelshe): The CurveCPClientSocket has a method called Disconnect.
// The CurveCPServerSocket has a method called Close.
// Unify them into either Close or Disconnect!!!
socket_->Disconnect();
socket_ = NULL;
}
}
bool TestClient::Start(const HostPortPair& server_host_port_pair,
int bytes_to_send,
CompletionCallback* callback) {
DCHECK(!socket_);
DCHECK(!finished_callback_);
finished_callback_ = callback;
bytes_to_read_ = bytes_to_send_ = bytes_to_send;
scoped_ptr<HostResolver> system_host_resolver(
CreateSystemHostResolver(1, 0, NULL));
SingleRequestHostResolver host_resolver(system_host_resolver.get());
HostResolver::RequestInfo request(server_host_port_pair);
AddressList addresses;
int rv = host_resolver.Resolve(request, &addresses, NULL, BoundNetLog());
if (rv != OK) {
LOG(ERROR) << "Could not resolve host";
return false;
}
socket_ = new CurveCPClientSocket(addresses, NULL, NetLog::Source());
rv = socket_->Connect(&connect_callback_);
if (rv == ERR_IO_PENDING)
return true;
OnConnectComplete(rv);
return rv == OK;
}
void TestClient::OnConnectComplete(int result) {
LOG(ERROR) << "Connect complete";
if (result < 0) {
LOG(ERROR) << "Connect failure: " << result;
errors_++;
Finish(result);
return;
}
DCHECK(bytes_to_send_); // We should have data to send.
ReadData();
DCHECK_EQ(bytes_to_send_, bytes_to_read_);
SendData();
}
void TestClient::OnReadComplete(int result) {
if (result <= 0) {
LOG(ERROR) << "Read failure: " << result;
errors_++;
Finish(result);
return;
}
if (!received_stream_.VerifyBytes(read_buffer_->data(), result)) {
if (!errors_) // Only log the first error.
LOG(ERROR) << "Client Received corrupt receive data!";
errors_++;
}
read_buffer_ = NULL;
bytes_to_read_ -= result;
// Now read more data...
if (bytes_to_read_)
ReadData();
else
Finish(OK);
}
void TestClient::OnWriteComplete(int result) {
LOG(ERROR) << "Write complete (remaining = " << bytes_to_send_ << ")";
if (result <= 0) {
errors_++;
Finish(result);
return;
}
write_buffer_->DidConsume(result);
bytes_to_send_ -= result;
if (!write_buffer_->BytesRemaining())
write_buffer_ = NULL;
if (bytes_to_send_)
SendData();
}
void TestClient::ReadData() {
DCHECK(!read_buffer_.get());
read_buffer_ = new IOBuffer(kMaxMessage);
int rv;
do {
rv = socket_->Read(read_buffer_, kMaxMessage, &read_callback_);
if (rv == ERR_IO_PENDING)
return;
OnReadComplete(rv); // Complete the read manually
} while (rv > 0);
}
void TestClient::SendData() {
DCHECK(bytes_to_send_); // We should have data to send.
const int kWriteChunkSize = 777; // 777 is more abusive
do {
if (!write_buffer_.get()) {
int bytes_to_send = std::min(kWriteChunkSize, bytes_to_send_);
scoped_refptr<IOBuffer> buffer(new IOBuffer(bytes_to_send));
sent_stream_.GetBytes(buffer->data(), bytes_to_send);
write_buffer_ = new DrainableIOBuffer(buffer, bytes_to_send);
}
int rv = socket_->Write(write_buffer_,
write_buffer_->BytesRemaining(),
&write_callback_);
if (rv == ERR_IO_PENDING)
return;
write_buffer_->DidConsume(rv);
bytes_to_send_ -= rv;
if (!write_buffer_->BytesRemaining())
write_buffer_ = NULL;
} while (bytes_to_send_);
}
void TestClient::Finish(int result) {
DCHECK(finished_callback_);
LOG(ERROR) << "TestClient Done!";
CompletionCallback* callback = finished_callback_;
finished_callback_ = NULL;
callback->Run(result);
}
} // namespace net