// DWBS ------------------------------------------------------------------ DWBS
//
// PLATFORM		: WIN32 PS2 PSP-INFRA XENON XBOX PS3
// PRODUCT		: BIT_DEMON
// VISIBILITY	: PUBLIC
//
// DWBS ------------------------------------------------------------------ DWBS

// PURPOSE : Represents a stream (TCP) connection.

#ifndef BD_STREAM_CONNECTION_H
#define BD_STREAM_CONNECTION_H

#include <bdCore/bdCore.h>
#include <bdCore/bdSocket/bdStreamSocket.h>
#include <bdCore/bdContainers/bdCircularBuffer.h>

#include <bdConnection/bdConnection.h>

// 2 bytes total message size + 1 byte encryption type
#define BD_STREAM_HEADER_SIZE 3

// 
#define BD_SEND_PLAINTEXT 0
#define BD_SEND_ENCRYPTED 1
#define BD_SIGNATURE_CHECK (0xDEADBEEF)

// Specifies the default size of the send/receive buffer for a stream connection
// This effectively limits the maximum message size that can be sent over a 
// stream connection. 
#define BD_STREAM_BUFFER_SIZE (0xffff)

// Maximum message size
#define BD_STREAM_MAX_MESSAGE_SIZE (BD_STREAM_BUFFER_SIZE - 10)

// Sends keep alive messages to the LSG. If no reply is received
// within 2 * BD_KEEP_ALIVE_PERIOD, the stream connection will be
// closed. This is used to perform end-to-end connectivity tests
#define BD_SEND_KEEP_ALIVE

#if defined BD_SEND_KEEP_ALIVE
/// Xbox platforms do not support TCP keep alive packets. Hence we send
/// our own keep alive messages to the LSG 
#define BD_KEEP_ALIVE_PERIOD 40
#endif

BD_REFERENCE(bdMessage);

BD_REFERENCE(bdStreamConnection);


/// A streaming connection is a TCP connection.
class bdStreamConnection : public bdConnection
{
	public:

		BD_DECLARE_NEW_AND_DELETE_OPERATORS

		/// Create a connection to addr.
		/// \param host[in]	The \b host to connect to. 
		bdStreamConnection( bdCommonAddrRef addr);

		/// Create a connection to host. Using this constructor, the connection uses
		/// the memory as specified by sendBuffer and recvBuffer resp.
		/// It is the client's responsibility to free buffers
		/// \param addr[in]	The \b host to connect to. 
		/// \param sendBuffer[in] A pointer to a chunk of memory to be used as send buffer
		/// \param recvBuffer[in] A pointer to a chunk of memory to be used as receive buffer
		/// \param bufSize of both the send and receive buffer
		bdStreamConnection( bdCommonAddrRef addr,
							void *sendBuffer,
                            void *recvBuffer,
                            bdUWord bufSize);


#if (defined BD_PLATFORM_XBOX) && (!defined BD_PLATFORM_XENON)
		/// \note XNetRegisterKey must be called before a stream connection
		/// is established.
		bdStreamConnection( bdCommonAddrRef addr, const bdSecurityID &secID);
#elif (defined BD_PLATFORM_XENON)
		/// \note XNetRegisterKey must be called before a stream connection
		/// is established.
		bdStreamConnection( bdAddr addr, 
							const bdSecurityID &secID);
#else // this only exists on non X* platforms
		/// Sets the connection's encryption key
		/// \param sessionKey[in] : The session key that will be used to 
		/// encrypt the data on this connection
		void setSessionKey(const bdUByte8 sessionKey[BD_ENCRYPTION_KEY_SIZE]);
#endif //#if (defined BD_PLATFORM_XBOX) || (defined BD_PLATFORM_XENON)

		/// Destructor.
		virtual ~bdStreamConnection();

		/// Does nothing. 
		virtual bdBool receive(bdUByte8 *buffer, 
							   const bdUInt32 bufferSize);

		/// Sends a message.
		///	\param message[in] The message to be sent. This function does not actually
		/// send the message, but rather enqueues it.
		/// \param encrypt[in] Flag to indicate whether the message should be encrypted
		/// or not
		/// \return True: the message was successfully enqueued. 
		virtual bdBool send(const bdMessageRef message, 
						    const bdBool encrypt = false);

		void sendRaw(bdUByte8 *buffer,
				     const bdUInt32 bufferSize);
		
		/// See documentation in base class. 
		virtual bdBool getMessageToDispatch(bdMessageRef &message);

		/// Tries to establish a connection. The underlying TCP socket is set to
		/// be non-blocking and this function returns immediately.
		virtual bdBool connect();

		/// Disconnects the connections
		virtual void disconnect();

		/// Closes the connection and calls any registered connections listeners.
		virtual void close();

		bdBool pump();

	protected:

		/// Never has any data to send.
		/// \return Zero always.
		virtual bdUInt getDataToSend(bdUByte8 *const buffer,
									 const bdUInt32 bufferSize);

		void callListenersConnect(const bdBool success);

		void callListenersDisconnect();

		void callListenersReconnect();

		bdBool receivedFullMessage();

	protected:

		bdCircularBuffer<bdUByte8> *m_incomingBuffer;
		bdCircularBuffer<bdUByte8> *m_outgoingBuffer;

		bdUInt16 m_messageSize;

		bdStreamSocket m_socket;

#if (defined BD_PLATFORM_XBOX) && (!defined BD_PLATFORM_XENON)
		bdSecurityID m_secID;

#elif (defined BD_PLATFORM_XENON)
		bdSecurityID m_secID;
		bdAddr m_serverAddr;
#else
		bdUByte8 m_sessionKey[BD_ENCRYPTION_KEY_SIZE];
		
		// Counter that is incremented for every message received. Used as a
		// seed for the IV vector
		bdUInt32 m_messageCount;

	
#endif // XBoxes

#if defined BD_SEND_KEEP_ALIVE

		// For timing the transmission of keep-alive packets
		bdStopwatch m_keepAliveTimer;

		// A timer that records the last time data was
		// received from the server
		bdStopwatch m_lastReceivedTimer;
#endif
};

#endif // BD_STREAM_CONNECTION_H


