blob: 576892eaeaa3345caffc2b998ded3f6588fbb79f [file] [log] [blame]
// Copyright (c) 2012 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/quic/quic_client_session.h"
#include "base/message_loop.h"
#include "base/stl_util.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/quic/quic_connection_helper.h"
#include "net/quic/quic_stream_factory.h"
#include "net/udp/datagram_client_socket.h"
namespace net {
QuicClientSession::QuicClientSession(QuicConnection* connection,
QuicConnectionHelper* helper,
QuicStreamFactory* stream_factory)
: QuicSession(connection, false),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(crypto_stream_(this)),
helper_(helper),
stream_factory_(stream_factory),
read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
read_pending_(false) {
}
QuicClientSession::~QuicClientSession() {
STLDeleteValues(&streams_);
}
QuicReliableClientStream* QuicClientSession::CreateOutgoingReliableStream() {
if (!crypto_stream_.handshake_complete()) {
DLOG(INFO) << "Crypto handshake not complete, no outgoing stream created.";
return NULL;
}
if (GetNumOpenStreams() >= get_max_open_streams()) {
DLOG(INFO) << "Failed to create a new outgoing stream. "
<< "Already " << GetNumOpenStreams() << " open.";
return NULL;
}
QuicReliableClientStream* stream =
new QuicReliableClientStream(GetNextStreamId(), this);
streams_[stream->id()] = stream;
ActivateStream(stream);
return stream;
}
QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
return &crypto_stream_;
};
int QuicClientSession::CryptoConnect(const CompletionCallback& callback) {
CryptoHandshakeMessage message;
message.tag = kCHLO;
crypto_stream_.SendHandshakeMessage(message);
if (IsCryptoHandshakeComplete()) {
return OK;
}
callback_ = callback;
return ERR_IO_PENDING;
}
ReliableQuicStream* QuicClientSession::CreateIncomingReliableStream(
QuicStreamId id) {
DLOG(ERROR) << "Server push not supported";
return NULL;
}
void QuicClientSession::CloseStream(QuicStreamId stream_id) {
QuicSession::CloseStream(stream_id);
StreamMap::iterator it = streams_.find(stream_id);
DCHECK(it != streams_.end());
if (it != streams_.end()) {
ReliableQuicStream* stream = it->second;
streams_.erase(it);
delete stream;
}
if (GetNumOpenStreams() == 0) {
stream_factory_->OnIdleSession(this);
}
}
void QuicClientSession::OnCryptoHandshakeComplete(QuicErrorCode error) {
if (!callback_.is_null()) {
callback_.Run(error == QUIC_NO_ERROR ? OK : ERR_UNEXPECTED);
}
}
void QuicClientSession::StartReading() {
if (read_pending_) {
return;
}
read_pending_ = true;
int rv = helper_->Read(read_buffer_, read_buffer_->size(),
base::Bind(&QuicClientSession::OnReadComplete,
weak_factory_.GetWeakPtr()));
if (rv == ERR_IO_PENDING) {
return;
}
// Data was read, process it.
// Schedule the work through the message loop to avoid recursive
// callbacks.
MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&QuicClientSession::OnReadComplete,
weak_factory_.GetWeakPtr(), rv));
}
void QuicClientSession::OnReadComplete(int result) {
read_pending_ = false;
// TODO(rch): Inform the connection about the result.
if (result > 0) {
scoped_refptr<IOBufferWithSize> buffer(read_buffer_);
read_buffer_ = new IOBufferWithSize(kMaxPacketSize);
QuicEncryptedPacket packet(buffer->data(), result);
IPEndPoint local_address;
IPEndPoint peer_address;
helper_->GetLocalAddress(&local_address);
helper_->GetPeerAddress(&peer_address);
// ProcessUdpPacket might result in |this| being deleted, so we
// use a weak pointer to be safe.
connection()->ProcessUdpPacket(local_address, peer_address, packet);
if (!connection()->connected()) {
stream_factory_->OnSessionClose(this);
return;
}
StartReading();
}
}
} // namespace net