// 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.
//
// A QuicSession, which demuxes a single connection to individual streams.

#ifndef NET_QUIC_QUIC_SESSION_H_
#define NET_QUIC_QUIC_SESSION_H_

#include <vector>

#include "base/compiler_specific.h"
#include "base/hash_tables.h"
#include "net/base/ip_endpoint.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_crypto_stream.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/reliable_quic_stream.h"

namespace net {

class QuicCryptoStream;
class ReliableQuicStream;
class VisitorShim;

namespace test {
class QuicSessionPeer;
}  // namespace test

class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
 public:
  QuicSession(QuicConnection* connection, bool is_server);

  virtual ~QuicSession();

  // QuicConnectionVisitorInterface methods:
  virtual bool OnPacket(const IPEndPoint& self_address,
                        const IPEndPoint& peer_address,
                        const QuicPacketHeader& header,
                        const std::vector<QuicStreamFrame>& frame) OVERRIDE;
  virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE;
  virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;
  // Not needed for HTTP.
  virtual void OnAck(AckedPackets acked_packets) OVERRIDE {}
  virtual bool OnCanWrite() OVERRIDE;

  // Called by streams when they want to write data to the peer.
  // Returns a pair with the number of bytes consumed from data, and a boolean
  // indicating if the fin bit was consumed.  This does not indicate the data
  // has been sent on the wire: it may have been turned into a packet and queued
  // if the socket was unexpectedly blocked.
  virtual QuicConsumedData WriteData(QuicStreamId id,
                                     base::StringPiece data,
                                     QuicStreamOffset offset,
                                     bool fin);
  // Called by streams when they want to close the stream in both directions.
  void SendRstStream(QuicStreamId id,
                     QuicErrorCode error,
                     QuicStreamOffset offset);

  // Removes the stream associated with 'stream_id' from the active stream map.
  virtual void CloseStream(QuicStreamId stream_id);

  // Returns true once the crypto handshake is complete.
  virtual bool IsCryptoHandshakeComplete();

  // Called by the QuicCryptoStream when the handshake completes.
  // If |error| is QUIC_NO_ERROR then the handshake was succesful,
  // otherwise it failed.
  virtual void OnCryptoHandshakeComplete(QuicErrorCode error);

  // Returns true if the stream existed previously and has been closed.
  // Returns false if the stream is still active or if the stream has
  // not yet been created.
  bool IsClosedStream(QuicStreamId id);

  QuicConnection* connection() { return connection_.get(); }
  size_t num_active_requests() const { return stream_map_.size(); }
  const IPEndPoint& peer_address() const {
    return connection_->peer_address();
  }
  QuicGuid guid() const { return connection_->guid(); }

  QuicPacketCreator::Options* options() { return connection()->options(); }

  // Returns the number of currently open streams, including those which have
  // been implicitly created.
  virtual size_t GetNumOpenStreams() const;

  void MarkWriteBlocked(QuicStreamId id);

 protected:
  // Creates a new stream, owned by the caller, to handle a peer-initiated
  // stream.  Returns NULL and does error handling if the stream can not be
  // created.
  virtual ReliableQuicStream* CreateIncomingReliableStream(QuicStreamId id) = 0;

  // Create a new stream, owned by the caller, to handle a locally-initiated
  // stream.  Returns NULL if max streams have already been opened.
  virtual ReliableQuicStream* CreateOutgoingReliableStream() = 0;

  // Return the reserved crypto stream.
  virtual QuicCryptoStream* GetCryptoStream() = 0;

  // Adds 'stream' to the active stream map.
  virtual void ActivateStream(ReliableQuicStream* stream);

  // Returns the stream id for a new stream.
  QuicStreamId GetNextStreamId();

  ReliableQuicStream* GetIncomingReliableStream(QuicStreamId stream_id);

  size_t get_max_open_streams() const {
    return max_open_streams_;
  }

 protected:
  // This is called after every call other than OnConnectionClose from the
  // QuicConnectionVisitor to allow post-processing once the work has been done.
  // In this case, it deletes streams given that it's safe to do so (no other
  // opterations are being done on the streams at this time)
  virtual void PostProcessAfterData();

  base::hash_map<QuicStreamId, ReliableQuicStream*>* streams() {
    return &stream_map_;
  }
  std::vector<ReliableQuicStream*>* closed_streams() {
    return &closed_streams_;
  }

 private:
  friend class test::QuicSessionPeer;
  friend class VisitorShim;

  typedef base::hash_map<QuicStreamId, ReliableQuicStream*> ReliableStreamMap;

  ReliableQuicStream* GetStream(const QuicStreamId stream_id);

  scoped_ptr<QuicConnection> connection_;

  // A shim to stand between the connection and the session, to handle stream
  // deletions.
  scoped_ptr<VisitorShim> visitor_shim_;

  std::vector<ReliableQuicStream*> closed_streams_;

  // Returns the maximum number of streams this connection can open.
  const size_t max_open_streams_;

  // Map from StreamId to pointers to streams that are owned by the caller.
  ReliableStreamMap stream_map_;
  QuicStreamId next_stream_id_;
  bool is_server_;

  // Set of stream ids that have been "implicitly created" by receipt
  // of a stream id larger than the next expected stream id.
  base::hash_set<QuicStreamId> implicitly_created_streams_;

  // A list of streams which need to write more data.
  std::list<QuicStreamId> write_blocked_streams_;

  QuicStreamId largest_peer_created_stream_id_;
};

}  // namespace net

#endif  // NET_QUIC_QUIC_SESSION_H_