blob: 94777b307d5a69edb548716eb1110b02c5b1c8ba [file] [log] [blame]
// Copyright 2015 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/p2p/quic_p2p_session.h"
#include <utility>
#include "base/callback_helpers.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/quic/p2p/quic_p2p_crypto_stream.h"
#include "net/quic/p2p/quic_p2p_stream.h"
#include "net/quic/quic_connection.h"
#include "net/socket/socket.h"
namespace net {
QuicP2PSession::QuicP2PSession(const QuicConfig& config,
const QuicP2PCryptoConfig& crypto_config,
std::unique_ptr<QuicConnection> connection,
std::unique_ptr<Socket> socket)
: QuicSession(connection.release(), config),
socket_(std::move(socket)),
crypto_stream_(new QuicP2PCryptoStream(this, crypto_config)),
read_buffer_(new IOBuffer(static_cast<size_t>(kMaxPacketSize))) {
DCHECK(config.negotiated());
// Non-null IP address needs to be passed here because QuicConnection uses
// ToString() to format addresses for logging and ToString() is not allowed
// for empty addresses.
// TODO(sergeyu): Fix QuicConnection and remove SetSelfAddress() call below.
this->connection()->SetSelfAddress(IPEndPoint(IPAddress::IPv4AllZeros(), 0));
}
QuicP2PSession::~QuicP2PSession() {}
void QuicP2PSession::Initialize() {
QuicSession::Initialize();
crypto_stream_->Connect();
DoReadLoop(OK);
}
void QuicP2PSession::SetDelegate(Delegate* delegate) {
delegate_ = delegate;
}
QuicCryptoStream* QuicP2PSession::GetCryptoStream() {
return crypto_stream_.get();
}
QuicP2PStream* QuicP2PSession::CreateIncomingDynamicStream(QuicStreamId id) {
QuicP2PStream* stream = new QuicP2PStream(id, this);
if (delegate_) {
delegate_->OnIncomingStream(stream);
}
ActivateStream(stream);
return stream;
}
QuicP2PStream* QuicP2PSession::CreateOutgoingDynamicStream(
SpdyPriority priority) {
QuicP2PStream* stream = new QuicP2PStream(GetNextOutgoingStreamId(), this);
if (stream) {
ActivateStream(stream);
}
return stream;
}
void QuicP2PSession::OnConnectionClosed(QuicErrorCode error,
const std::string& error_details,
ConnectionCloseSource source) {
QuicSession::OnConnectionClosed(error, error_details, source);
socket_.reset();
if (delegate_) {
Delegate* delegate = delegate_;
delegate_ = nullptr;
delegate->OnConnectionClosed(error);
}
}
void QuicP2PSession::DoReadLoop(int result) {
while (error() == QUIC_NO_ERROR) {
switch (read_state_) {
case READ_STATE_DO_READ:
CHECK_EQ(result, OK);
result = DoRead();
break;
case READ_STATE_DO_READ_COMPLETE:
result = DoReadComplete(result);
break;
default:
NOTREACHED() << "read_state_: " << read_state_;
break;
}
if (result < 0)
break;
}
}
int QuicP2PSession::DoRead() {
DCHECK_EQ(read_state_, READ_STATE_DO_READ);
read_state_ = READ_STATE_DO_READ_COMPLETE;
if (!socket_) {
return ERR_SOCKET_NOT_CONNECTED;
}
return socket_->Read(
read_buffer_.get(), kMaxPacketSize,
base::Bind(&QuicP2PSession::DoReadLoop, base::Unretained(this)));
}
int QuicP2PSession::DoReadComplete(int result) {
DCHECK_EQ(read_state_, READ_STATE_DO_READ_COMPLETE);
read_state_ = READ_STATE_DO_READ;
if (result <= 0) {
connection()->CloseConnection(QUIC_PACKET_READ_ERROR, "packet read error",
ConnectionCloseBehavior::SILENT_CLOSE);
return result;
}
QuicReceivedPacket packet(read_buffer_->data(), result, clock_.Now());
connection()->ProcessUdpPacket(connection()->self_address(),
connection()->peer_address(), packet);
return OK;
}
} // namespace net