/*
 * libjingle
 * Copyright 2004--2008, Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// SecureTunnelSessionClient and SecureTunnelSession.
// SecureTunnelSessionClient extends TunnelSessionClient to exchange
// certificates as part of the session description.
// SecureTunnelSession is a TunnelSession that wraps the underlying
// tunnel stream into an SSLStreamAdapter.

#ifndef TALK_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_
#define TALK_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_

#include <string>

#include "talk/base/sslidentity.h"
#include "talk/base/sslstreamadapter.h"
#include "talk/session/tunnel/tunnelsessionclient.h"

namespace cricket {

class SecureTunnelSession;  // below

// SecureTunnelSessionClient

// This TunnelSessionClient establishes secure tunnels protected by
// SSL/TLS. The PseudoTcpChannel stream is wrapped with an
// SSLStreamAdapter. An SSLIdentity must be set or generated.
//
// The TunnelContentDescription is extended to include the client and
// server certificates. The initiator acts as the client. The session
// initiate stanza carries a description that contains the client's
// certificate, and the session accept response's description has the
// server certificate added to it.

class SecureTunnelSessionClient : public TunnelSessionClient {
 public:
  // The jid is used as the name for sessions for outgoing tunnels.
  // manager is the SessionManager to which we register this client
  // and its sessions.
  SecureTunnelSessionClient(const buzz::Jid& jid, SessionManager* manager);

  // Configures this client to use a preexisting SSLIdentity.
  // The client takes ownership of the identity object.
  // Use either SetIdentity or GenerateIdentity, and only once.
  void SetIdentity(talk_base::SSLIdentity* identity);

  // Generates an identity from nothing.
  // Returns true if generation was successful.
  // Use either SetIdentity or GenerateIdentity, and only once.
  bool GenerateIdentity();

  // Returns our identity for SSL purposes, as either set by
  // SetIdentity() or generated by GenerateIdentity(). Call this
  // method only after our identity has been successfully established
  // by one of those methods.
  talk_base::SSLIdentity& GetIdentity() const;

  // Inherited methods
  virtual void OnIncomingTunnel(const buzz::Jid& jid, Session *session);
  virtual bool ParseContent(SignalingProtocol protocol,
                            const buzz::XmlElement* elem,
                            const ContentDescription** content,
                            ParseError* error);
  virtual bool WriteContent(SignalingProtocol protocol,
                            const ContentDescription* content,
                            buzz::XmlElement** elem,
                            WriteError* error);
  virtual SessionDescription* CreateOffer(
      const buzz::Jid &jid, const std::string &description);
  virtual SessionDescription* CreateAnswer(
      const SessionDescription* offer);

 protected:
  virtual TunnelSession* MakeTunnelSession(
      Session* session, talk_base::Thread* stream_thread,
      TunnelSessionRole role);

 private:
  // Our identity (key and certificate) for SSL purposes. The
  // certificate part will be communicated within the session
  // description. The identity will be passed to the SSLStreamAdapter
  // and used for SSL authentication.
  talk_base::scoped_ptr<talk_base::SSLIdentity> identity_;

  DISALLOW_EVIL_CONSTRUCTORS(SecureTunnelSessionClient);
};

// SecureTunnelSession:
// A TunnelSession represents one session for one client. It
// provides the actual tunnel stream and handles state changes.
// A SecureTunnelSession is a TunnelSession that wraps the underlying
// tunnel stream into an SSLStreamAdapter.

class SecureTunnelSession : public TunnelSession {
 public:
  // This TunnelSession will tie together the given client and session.
  // stream_thread is passed to the PseudoTCPChannel: it's the thread
  // designated to interact with the tunnel stream.
  // role is either INITIATOR or RESPONDER, depending on who is
  // initiating the session.
  SecureTunnelSession(SecureTunnelSessionClient* client, Session* session,
                      talk_base::Thread* stream_thread,
                      TunnelSessionRole role);

  // Returns the stream that implements the actual P2P tunnel.
  // This may be called only once. Caller is responsible for freeing
  // the returned object.
  virtual talk_base::StreamInterface* GetStream();

 protected:
  // Inherited method: callback on accepting a session.
  virtual void OnAccept();

  // Helper method for GetStream() that Instantiates the
  // SSLStreamAdapter to wrap the PseudoTcpChannel's stream, and
  // configures it with our identity and role.
  talk_base::StreamInterface* MakeSecureStream(
      talk_base::StreamInterface* stream);

  // Our role in requesting the tunnel: INITIATOR or
  // RESPONDER. Translates to our role in SSL negotiation:
  // respectively client or server. Also indicates which slot of the
  // SecureTunnelContentDescription our cert goes into: client-cert or
  // server-cert respectively.
  TunnelSessionRole role_;

  // This is the stream representing the usable tunnel endpoint.  It's
  // a StreamReference wrapping the SSLStreamAdapter instance, which
  // further wraps a PseudoTcpChannel::InternalStream. The
  // StreamReference is because in the case of CreateTunnel(), the
  // stream endpoint is returned early, but we need to keep a handle
  // on it so we can setup the peer certificate when we receive it
  // later.
  talk_base::scoped_ptr<talk_base::StreamReference> ssl_stream_reference_;

  DISALLOW_EVIL_CONSTRUCTORS(SecureTunnelSession);
};

}  // namespace cricket

#endif  // TALK_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_