Page MenuHomePhorge

Connection.h
No OneTemporary

Size
17 KB
Referenced Files
None
Subscribers
None

Connection.h

#ifndef _CONNECTION_H_
#define _CONNECTION_H_
#include <echo/Types.h>
#include <echo/Network/ConnectionDetails.h>
#include <list>
#include <vector>
#include <map>
#include <echo/Kernel/Mutex.h>
#include <echo/Chrono/CountDownTimer.h>
#include <boost/function.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
namespace Echo
{
class DataPacket;
class DataPacketHeader;
class Connection;
class ConnectionOwner;
class NetworkManager;
class Connection : public enable_shared_from_this<Connection>
{
public:
struct States
{
enum _
{
DISCONNECTED,
CONNECTING,
CONNECTED
};
};
typedef States::_ State;
/**
* PacketCallback
* @param first parameter is the connection.
* @param second parameter is the incoming DataPacket.
*/
typedef boost::function<void(shared_ptr<Connection>, shared_ptr<DataPacket>)> PacketCallback;
static boost::arg<1> ConnectionPlaceholder;
static boost::arg<2> DataPacketPlaceholder;
/**
* LabelledPacketCallback
* @param first parameter is the connection.
* @param second parameter is the data packet that contained the labelled data.
* @param third is a pointer to the data in the data packet starting at the first byte after the label.
* @param fourth the length of the data in bytes from the (the DataPacket data size minus the label+meta info size).
*/
typedef boost::function<void(shared_ptr<Connection>, shared_ptr<DataPacket>, const u8*, Size)> LabelledPacketCallback;
static boost::arg<2> PacketContentsPlaceholder;
/**
* DisconnectCallback
* @param first parameter is the connection.
*/
typedef boost::function<void(shared_ptr<Connection>)> DisconnectCallback;
/**
* ConnectCallback
* @param first parameter is the connection.
*/
typedef boost::function<void(shared_ptr<Connection>)> ConnectCallback;
//These packets are used internally for control
struct PacketTypes
{
enum Value
{
LABELLED_PACKET =0xFFFFFFFF,
REMOTE_DETAILS =0xFEFEFEFE, // Remote details packet, sent internally to determine
// communication details with the remote host, such as
// protocol version and endian format. The ID needs to
// read the same in big and little endian.
MINIMUM_RESERVED_PACKET_ID =0xF0000000 // Packets IDs after this value are reserved
};
};
typedef PacketTypes::Value PacketType;
struct PacketPoolResizeActions
{
enum Value{ RESIZE_ENTIRE_POOL=1, //Re-allocates enough memory for the
//pool size.
AFFECT_PACKET_COUNT_ONLY=2, //Attempts to avoid a reallocation
//and instead just affect the number
//of available packets.
};
};
typedef PacketPoolResizeActions::Value PacketPoolResizeAction;
static void SetPlatformBigEndian(bool isBigEndian) {mPlatformBigEndian=isBigEndian;}
static bool IsPlatformBigEndian() {return mPlatformBigEndian;}
NetworkManager& GetNetworkManager() {return mNetworkManager;}
bool Connect();
bool Disconnect();
void SetOwner(ConnectionOwner* owner);
ConnectionOwner* GetOwner() const {return mOwner;}
std::string GetFriendlyIdentifier();
shared_ptr<DataPacket> NewDataPacket();
shared_ptr<DataPacket> NewDataPacket(u32 packetTypeID, u32 size);
shared_ptr<DataPacket> NewDataPacket(std::string label, u32 size);
//Returns true if there are still packets queued to notify
bool NotifyAnyReceivedPackets();
size_t GetNumReceviedPackets() const {return mReceviedPackets.size();}
/**
* Send a DataPacket
* @param packet the packet
* @param prioritise If true the packet will be sent before of any packets currently queued.
*/
void SendDataPacket(shared_ptr<DataPacket> packet, bool prioritise = false);
/**
* Helper method to send data.
* This method builds a DataPacket for you.
* @param data The data
* @param dataSize The number of bytes to send
* @param packetID The packet ID to send the data as.
* @param prioritise If true the packet will be sent before of any packets currently queued.
*/
void SendData(const u8* data, u32 dataSize, u32 packetID, bool prioritise = false);
/**
* Helper method to send a string.
* @param message the message to send.
* @param packetID the packet ID to send the message as.
* @param prioritise If true the packet will be sent before of any packets currently queued.
*/
void SendMessage(const std::string& message, u32 packetID, bool prioritise = false);
/**
* Send a control packet.
* A control packet has an ID and no data. Control packets are designed to be
* used for notification.
* @param packetTypeID the ID of the packet you want to send.
* @param prioritise If true the packet will be sent before of any packets currently queued.
*/
void SendControlPacket(u32 packetTypeID, bool prioritise = false);
/**
* Helper method to send a labelled DataPacket.
* @param prioritise If true the packet will be sent before of any packets currently queued.
*/
void SendLabelledPacket(const std::string& label, const u8* data, u32 dataSize, bool prioritise = false);
/**
* Helper method to send a labeled DataPacket.
* @param prioritise If true the packet will be sent before of any packets currently queued.
*/
template< typename T>
void SendLabelledPacket(const std::string& label, const T& content, bool prioritise = false)
{
//TODO: try and catch.
std::string contentAsString=boost::lexical_cast<std::string>(content);
SendLabelledPacket(label,reinterpret_cast<const u8*>(contentAsString.c_str()),contentAsString.length(),prioritise);
}
/**
* Helper method to send a labeled DataPacket with a string as the content.
* @param prioritise If true the packet will be sent before of any packets currently queued.
*/
void SendLabelledPacket(const std::string& label, const std::string& content, bool prioritise = false);
/**
* Helper method to send a labeled DataPacket with multiple strings as the content.
* @param prioritise If true the packet will be sent before of any packets currently queued.
*/
void SendLabelledPacket(const std::string& label, const std::vector<std::string>& content, bool prioritise = false);
/**
* Attempts to receive data.
* Data received will be used to build DataPacket objects. When a full packet
* is received it will be added to the list of received packets. The number of
* packets available will be returned.
* This method will call _recv() then pass the return value into
* _HandleRecvError(). If _HandleRecvError() returns false and the _recv()
* return value is less than 0 then that value will be returned from this method,
* otherwise -1 will used to indicate an error. Positive return values from this
* method indicate the number of packets available.
* @note You do not normally need to call this method manually. The NetworkSystem
* managing the connection will call it and deal with firing callbacks.
* @note Error codes are system specific, which is why the handle methods are used.
* @return less than 0 on error, otherwise the number of complete packets available.
*/
int Receive();
/**
* Attempts to send data.
* This method will call _send() then pass the return value into _HandleWriteError().
* @note You do not normally need to call this method manually.
* @note Error codes are system specific, which is why the handle methods are used.
*/
void Write(bool reenable);
/**
* Used to change the state of the connection flag.
* @note This is used by network systems and should not be used in attempt to connect
* or disconnect. Use the dedicated methods for that which will perform the desired
* action.
* @parm state The new state, if it is not connected the can send flag is set to false.
*/
void SetState(State state);
bool IsConnected() const {return (mState==States::CONNECTED);}
/**
* Get whether the connection is in a connecting state or not.
*/
bool GetConnecting() const {return (mState==States::CONNECTING);}
const ConnectionDetails& GetConnectionDetails() const { return mConnectionDetails; }
void SetConnectionDetails(const ConnectionDetails& val) { mConnectionDetails = val; }
/**
* Register a Packet Callback method for a labelled packet.
* Callbacks can be registered for incoming packets which will be called when the
* incoming packet is identified as a labelled packet.
* @param label The label in which to match a labelled incoming packet.
* @param callback The callback to call if the label matches the packet label.
*/
void RegisterLabelledPacketCallback(const std::string& label, LabelledPacketCallback callback);
/**
* Register a Packet Callback method for a packet.
* Callbacks can be registered for incoming packets which will be called when the
* incoming packet has the specified ID. This allows you to register callbacks for
* packets with different ids and not have to handle the use of the packet in
* ReceivedPacket.
* @note Some packet IDs are reserved, see PacketTypes for more information.
* @param packetID The id in which to match with the id of an incoming packet.
* @param callback The callback to call if the id matches the packet id.
*/
void RegisterPacketCallback(u32 packetID, PacketCallback callback);
/**
* Register a "Connect" Callback method with an identifier.
* @note The callback will only be called if the callback is registered before the connection event.
* @note To remove the callback you need to reference the identifier. This is because boost functions cannot be compared.
* @param identifier The identifier in which to reference the registration.
* @param callback The callback to call when the connection connects.
*/
void RegisterConnectCallback(const std::string& identifier, ConnectCallback callback);
/**
* Register a "Disconnect" Callback method with an identifier.
* @note To remove the callback you need to reference the identifier. This is because boost functions cannot be compared.
* @param identifier The identifier in which to reference the registration.
* @param callback The callback to call when the connection connects.
*/
void RegisterDisconnectCallback(const std::string& identifier, DisconnectCallback callback);
/**
* Clear all labelled packet callbacks with corresponding label.
* @param label
*/
void ClearLabelledPacketCallbacks(const std::string& label);
/**
* Clear all labelled packet callbacks.
*/
void ClearAllLabelledPacketCallbacks();
/**
* Clear all packet callbacks for corresponding packet ID.
* @param packetID
*/
void ClearPacketIDCallbacks(u32 packetID);
/**
* Clear all packet id callbacks that were registered with RegisterPacketCallback(u32,PacketCallback)
*/
void ClearAllPacketIDCallbacks();
/**
* Clear all labelled and packet ID callbacks.
*/
void ClearAllPacketCallbacks();
/**
* Clear connect callbacks corresponding to identifier.
* @param identifier
*/
void ClearConnectCallbacks(const std::string& identifier);
/**
* Clear all of the connect callbacks.
*/
void ClearAllConnectCallbacks();
/**
* Clear disconnect callbacks corresponding to identifier.
* @param identifier
*/
void ClearDisconnectCallbacks(const std::string& identifier);
/**
* Clear all of the disconnect callbacks.
* @param attemptReconnet
*/
void ClearAllDisconnectCallbacks();
/**
* Clear all callbacks.
*/
inline void ClearAllCallbacks()
{
ClearAllPacketCallbacks();
ClearAllConnectCallbacks();
ClearAllDisconnectCallbacks();
}
void SetAutoAttemptReconnect(bool attemptReconnet){mAutoAttemptReconnect=attemptReconnet;}
bool GetAutoAttemptReconnect() const {return mAutoAttemptReconnect;}
/**
* Set the auto reconnect time.
* @note The Connection will configure a CountDownTimer to process the reconnect. CountDownTimers
* are Tasks so they are updated during Kernel updates. This means that if an ExecutionModel that
* does not update regularly is in use (such as the NetworkExecutionModel) the auto reconnect time
* may turn out to be longer than what is configured in the Connection.
* @param seconds how long to wait before attempting to reconnect if the connection has disconnected.
*/
void SetAutoAttemptReconnectTime(Seconds seconds);
/**
* This method will be called internally or by a network system to disconnect the connection.
* If the connection is connected then this method at the very minimum should:
* - Set the connection into the disconnected state using SetConnected(false) then;
* - call mManager.UpdateConnect(shared_from_this()) to notify the manager to process
* the dropped connection.
* @return true if the connection changed state to disconnect otherwise false the connection
* is already disconnected or if something prevents the connection from disconnecting.
*/
virtual bool _Disconnect()=0;
/**
* Check whether or not the remote host is big endian.
* @return true if the remote host is big endian, otherwise false to indicate little endian.
*/
bool IsRemoteBigEndian() const {return mIsRemoteBigEndian;}
protected:
static bool mPlatformBigEndian;
NetworkManager& mNetworkManager;
//Only the NetworkManager can clean up a connection
friend class NetworkManager;
Connection(NetworkManager& manager);
virtual ~Connection();
/**
* Called by NetworkManager after receiving remote details.
*/
void SetRemoteBigEndian(bool isBigEndian) {mIsRemoteBigEndian = isBigEndian;}
/**
* Process the remote details packet after initial connection.
*/
void OnRemoteDetails(shared_ptr<Connection> connection, shared_ptr<DataPacket> dataPacket);
void SendHostDetails();
shared_ptr<DataPacket> mHeaderPacket;
shared_ptr<DataPacket> mCurrentPacket;
ConnectionOwner* mOwner;
static const u32 DATAPACKET_TEMPBUFFER_SIZE=16384;
u8 mTempBuffer[DATAPACKET_TEMPBUFFER_SIZE];
State mState;
bool mCanSend;
bool mAutoAttemptReconnect; /// If true will attempt to automatically reconnect if the connection drops.
bool mManualDisconnect; /// Used to determine whether we should automatically reconnect.
Mutex mQueuedPacketsMutex;
Mutex mReceviedPacketsMutex;
std::list< shared_ptr<DataPacket> > mQueuedPackets;
std::list< shared_ptr<DataPacket> > mReceviedPackets;
s32 mQueuedData; //Count of queued Data only packets
bool mHeaderSent; //Flag: concerned with mQueuedPackets
bool mIsRemoteBigEndian;
/**
* Normally the implementation is just a wrapper around a send method.
* The method should be non-blocking.
* @return the number of bytes that have been sent or if there was an error,
* an error code less than 0.
*/
virtual int _send(const u8 * buf, int len, int flags)=0;
/**
* Normally the implementation is just a wrapper around a receive method.
* The method should be non-blocking.
* @return the number of bytes that have been recevied or if there was an error,
* an error code less than 0.
*/
virtual int _recv(u8 * buf, int len, int flags)=0;
/**
* Handle errors from the call to _recv().
* The implementation should call _Disconnect() if there was an error that results
* in the connection becoming disconnected.
*/
virtual bool _HandleRecvError(int code)=0;
/**
* Handle errors from the call to _send().
* The implementation should call _Disconnect() if there was an error that results
* in the connection becoming disconnected.
*/
virtual bool _HandleWriteError(int code)=0;
virtual void _notifyOwner(shared_ptr<DataPacket> packet);
/**
* Called to process dropped connections and notify the connection owner.
* @note This method is called by the NetworkManager.
*/
virtual void _dropped();
/**
* Called to process dropped connections and notify the connection owner.
* @note This method is called by the NetworkManager when a connection is established.
*/
virtual void _established();
/**
* Called to start a connection attempt.
* @return false if there were problems, otherwise true.
*/
virtual bool _Connect()=0;
ConnectionDetails mConnectionDetails;
CountDownTimer mReconnectTimer;
static const u32 mUnreasonableDataSize; //Data size we consider to be unreasonable.
private:
std::map< u32, std::vector<PacketCallback> > mPacketCallbacks;
std::map< std::string, std::vector<LabelledPacketCallback> > mLabelledPacketCallbacks;
std::map< std::string, std::vector<ConnectCallback> > mConnectCallbacks;
std::map< std::string, std::vector<DisconnectCallback> > mDisconnectCallbacks;
void ProcessReceivedPacket(shared_ptr<DataPacket> packet);
void ProcessLabelledPacket(shared_ptr<Connection> connection, shared_ptr<DataPacket> packet);
};
}
#endif

File Metadata

Mime Type
text/x-c++
Expires
Thu, Jan 16, 1:14 AM (7 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72116
Default Alt Text
Connection.h (17 KB)

Event Timeline