1 // Copyright (c) 2012 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.
5 #include "net/quic/quic_client_session.h"
7 #include "base/message_loop.h"
8 #include "base/stl_util.h"
9 #include "base/string_number_conversions.h"
10 #include "base/values.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13 #include "net/quic/quic_connection_helper.h"
14 #include "net/quic/quic_stream_factory.h"
15 #include "net/udp/datagram_client_socket.h"
19 QuicClientSession::QuicClientSession(QuicConnection
* connection
,
20 QuicConnectionHelper
* helper
,
21 QuicStreamFactory
* stream_factory
)
22 : QuicSession(connection
, false),
23 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
24 ALLOW_THIS_IN_INITIALIZER_LIST(crypto_stream_(this)),
26 stream_factory_(stream_factory
),
27 read_buffer_(new IOBufferWithSize(kMaxPacketSize
)),
28 read_pending_(false) {
31 QuicClientSession::~QuicClientSession() {
34 QuicReliableClientStream
* QuicClientSession::CreateOutgoingReliableStream() {
35 if (!crypto_stream_
.handshake_complete()) {
36 DLOG(INFO
) << "Crypto handshake not complete, no outgoing stream created.";
39 if (GetNumOpenStreams() >= get_max_open_streams()) {
40 DLOG(INFO
) << "Failed to create a new outgoing stream. "
41 << "Already " << GetNumOpenStreams() << " open.";
44 QuicReliableClientStream
* stream
=
45 new QuicReliableClientStream(GetNextStreamId(), this);
46 ActivateStream(stream
);
50 QuicCryptoClientStream
* QuicClientSession::GetCryptoStream() {
51 return &crypto_stream_
;
54 int QuicClientSession::CryptoConnect(const CompletionCallback
& callback
) {
55 CryptoHandshakeMessage message
;
57 crypto_stream_
.SendHandshakeMessage(message
);
59 if (IsCryptoHandshakeComplete()) {
64 return ERR_IO_PENDING
;
67 ReliableQuicStream
* QuicClientSession::CreateIncomingReliableStream(
69 DLOG(ERROR
) << "Server push not supported";
73 void QuicClientSession::CloseStream(QuicStreamId stream_id
) {
74 QuicSession::CloseStream(stream_id
);
76 if (GetNumOpenStreams() == 0) {
77 stream_factory_
->OnIdleSession(this);
81 void QuicClientSession::OnCryptoHandshakeComplete(QuicErrorCode error
) {
82 if (!callback_
.is_null()) {
83 callback_
.Run(error
== QUIC_NO_ERROR
? OK
: ERR_UNEXPECTED
);
87 void QuicClientSession::StartReading() {
92 int rv
= helper_
->Read(read_buffer_
, read_buffer_
->size(),
93 base::Bind(&QuicClientSession::OnReadComplete
,
94 weak_factory_
.GetWeakPtr()));
95 if (rv
== ERR_IO_PENDING
) {
99 // Data was read, process it.
100 // Schedule the work through the message loop to avoid recursive
102 MessageLoop::current()->PostTask(
104 base::Bind(&QuicClientSession::OnReadComplete
,
105 weak_factory_
.GetWeakPtr(), rv
));
108 void QuicClientSession::CloseSessionOnError(int error
) {
109 while (!streams()->empty()) {
110 ReliableQuicStream
* stream
= streams()->begin()->second
;
111 QuicStreamId id
= stream
->id();
112 static_cast<QuicReliableClientStream
*>(stream
)->OnError(error
);
115 stream_factory_
->OnSessionClose(this);
118 Value
* QuicClientSession::GetInfoAsValue(const HostPortPair
& pair
) const {
119 DictionaryValue
* dict
= new DictionaryValue();
120 dict
->SetString("host_port_pair", pair
.ToString());
121 dict
->SetInteger("open_streams", GetNumOpenStreams());
122 dict
->SetString("peer_address", peer_address().ToString());
123 dict
->SetString("guid", base::Uint64ToString(guid()));
127 void QuicClientSession::OnReadComplete(int result
) {
128 read_pending_
= false;
129 // TODO(rch): Inform the connection about the result.
131 scoped_refptr
<IOBufferWithSize
> buffer(read_buffer_
);
132 read_buffer_
= new IOBufferWithSize(kMaxPacketSize
);
133 QuicEncryptedPacket
packet(buffer
->data(), result
);
134 IPEndPoint local_address
;
135 IPEndPoint peer_address
;
136 helper_
->GetLocalAddress(&local_address
);
137 helper_
->GetPeerAddress(&peer_address
);
138 // ProcessUdpPacket might result in |this| being deleted, so we
139 // use a weak pointer to be safe.
140 connection()->ProcessUdpPacket(local_address
, peer_address
, packet
);
141 if (!connection()->connected()) {
142 stream_factory_
->OnSessionClose(this);