SyncProtocol.hpp   SyncProtocol.hpp 
skipping to change at line 35 skipping to change at line 35
#include <QAbstractSocket> #include <QAbstractSocket>
#include <QUuid> #include <QUuid>
//! Contains sync protocol data definitions shared between client and serve r //! Contains sync protocol data definitions shared between client and serve r
namespace SyncProtocol namespace SyncProtocol
{ {
//Important: All data should use the sized typedefs provided by Qt (i.e. qi nt32 instead of 4 byte int on x86) //Important: All data should use the sized typedefs provided by Qt (i.e. qi nt32 instead of 4 byte int on x86)
//! Should be changed with every breaking change //! Should be changed with every breaking change
const quint8 SYNC_PROTOCOL_VERSION = 1; const quint8 SYNC_PROTOCOL_VERSION = 2;
const QDataStream::Version SYNC_DATASTREAM_VERSION = QDataStream::Qt_5_0; const QDataStream::Version SYNC_DATASTREAM_VERSION = QDataStream::Qt_5_0;
//! Magic value for protocol used during connection. Should NEVER change. //! Magic value for protocol used during connection. Should NEVER change.
const QByteArray SYNC_MAGIC_VALUE = "StellariumSyncPluginProtocol"; const QByteArray SYNC_MAGIC_VALUE = "StellariumSyncPluginProtocol";
typedef quint16 tPayloadSize; typedef quint16 tPayloadSize;
//! All messages are preceded by this //! All messages are preceded by this
struct SyncHeader struct SyncHeader
{ {
quint8 msgType; //The SyncMessageType of the data quint8 msgType; //The SyncMessageType of the data
SyncProtocol::tPayloadSize dataSize; //The size of the data part SyncProtocol::tPayloadSize dataSize; //The size of the data part
//TODO maybe add checksum?
}; };
//! Write a SyncHeader to a DataStream //! Write a SyncHeader to a DataStream
QDataStream& operator<<(QDataStream& out, const SyncHeader& header); QDataStream& operator<<(QDataStream& out, const SyncHeader& header);
//! Read a SyncHeader from a DataStream //! Read a SyncHeader from a DataStream
QDataStream& operator>>(QDataStream& in, SyncHeader& header); QDataStream& operator>>(QDataStream& in, SyncHeader& header);
const qint64 SYNC_HEADER_SIZE = sizeof(quint8) + sizeof(tPayloadSize); //3 byte const qint64 SYNC_HEADER_SIZE = sizeof(quint8) + sizeof(tPayloadSize); //3 byte
const qint64 SYNC_MAX_PAYLOAD_SIZE = (2<<15) - 1; // 65535 const qint64 SYNC_MAX_PAYLOAD_SIZE = (2<<15) - 1; // 65535
const qint64 SYNC_MAX_MESSAGE_SIZE = SYNC_HEADER_SIZE + SYNC_MAX_PAYLOAD_SI ZE; const qint64 SYNC_MAX_MESSAGE_SIZE = SYNC_HEADER_SIZE + SYNC_MAX_PAYLOAD_SI ZE;
//! Contains the possible message types. The enum value is used as an ID to identify the message type over the network. //! Contains the possible message types. The enum value is used as an ID to identify the message type over the network.
//! The classes handling these messages are defined in SyncMessages.hpp //! The classes handling these messages are defined in SyncMessages.hpp
enum SyncMessageType enum SyncMessageType
{ {
ERROR, //sent to the other party on protocol/auth error with a messa ge, connection will be dropped afterwards ERROR, //sent to the other party on protocol/auth error with a messa ge, connection will be dropped afterwards
SERVER_CHALLENGE, //sent as a challenge to the client on establishme nt of connection SERVER_CHALLENGE, //sent as a challenge to the client on establishme nt of connection
CLIENT_CHALLENGE_RESPONSE, //sent as a reply to the challenge CLIENT_CHALLENGE_RESPONSE, //sent as a reply to the challenge
SERVER_CHALLENGERESPONSEVALID, //sent from the server to the client after valid client hello was received. SERVER_CHALLENGERESPONSEVALID, //sent from the server to the client after valid client hello was received.
ALIVE, //sent from a peer after no data was sent for about 5 seconds to indicate it is still alive
//all messages below here can only be sent from authenticated peers //all messages below here can only be sent from authenticated peers
TIME, //time jumps + time scale updates TIME, //time jumps + time scale updates
LOCATION, //location changes LOCATION, //location changes
SELECTION, SELECTION, //current selection changed
STELPROPERTY, //stelproperty updates
VIEW, //view change
FOV, //fov change
ALIVE, //sent from a peer after no data was sent for about 5 seconds MSGTYPE_MAX = FOV,
to indicate it is still alive
MSGTYPE_MAX = ALIVE,
MSGTYPE_SIZE = MSGTYPE_MAX+1 MSGTYPE_SIZE = MSGTYPE_MAX+1
}; };
inline QDebug& operator<<(QDebug& deb, SyncMessageType msg) inline QDebug& operator<<(QDebug& deb, SyncMessageType msg)
{ {
switch (msg) { switch (msg) {
case SyncProtocol::ERROR: case SyncProtocol::ERROR:
deb<<"ERROR"; deb<<"ERROR";
break; break;
case SyncProtocol::SERVER_CHALLENGE: case SyncProtocol::SERVER_CHALLENGE:
skipping to change at line 102 skipping to change at line 104
break; break;
case SyncProtocol::TIME: case SyncProtocol::TIME:
deb<<"TIME"; deb<<"TIME";
break; break;
case SyncProtocol::LOCATION: case SyncProtocol::LOCATION:
deb<<"LOCATION"; deb<<"LOCATION";
break; break;
case SyncProtocol::SELECTION: case SyncProtocol::SELECTION:
deb<<"SELECTION"; deb<<"SELECTION";
break; break;
case SyncProtocol::STELPROPERTY:
deb<<"STELPROPERTY";
break;
case SyncProtocol::VIEW:
deb<<"VIEW";
break;
case SyncProtocol::FOV:
deb<<"FOV";
break;
case SyncProtocol::ALIVE: case SyncProtocol::ALIVE:
deb<<"ALIVE"; deb<<"ALIVE";
break; break;
default: default:
deb<<"UNKNOWN("<<int(msg)<<')'; deb<<"UNKNOWN("<<int(msg)<<')';
break; break;
} }
return deb; return deb;
} }
}
//! Base interface for the messages themselves, allowing to serialize/deser ialize them //! Base interface for the messages themselves, allowing to serialize/deser ialize them
class SyncMessage class SyncMessage
{ {
public: public:
virtual ~SyncMessage() {} virtual ~SyncMessage() {}
//! Subclasses must return the message type this message represents //! Subclasses must return the message type this message represents
virtual SyncProtocol::SyncMessageType getMessageType() const = 0; virtual SyncProtocol::SyncMessageType getMessageType() const = 0;
//! Writes a full message (with header) to the specified byte array. //! Writes a full message (with header) to the specified byte array.
//! Returns the total message size. If zero, the payload is too larg e for a SyncMessage. //! Returns the total message size. If zero, the payload is too larg e for a SyncMessage.
qint64 createFullMessage(QByteArray& target) const; qint64 createFullMessage(QByteArray& target) const;
//! Subclasses should override this to serialize their contents to t he data stream. //! Subclasses should override this to serialize their contents to t he data stream.
//! The default implementation writes nothing. //! The default implementation writes nothing.
virtual void serialize(QDataStream& stream) const; virtual void serialize(QDataStream& stream) const;
//! Subclasses should override this to load their contents from the data stream. //! Subclasses should override this to load their contents from the data stream.
//! The default implementation expects a zero dataSize, and reads no thing. //! The default implementation expects a zero dataSize, and reads no thing.
virtual bool deserialize(QDataStream& stream, SyncProtocol::tPayload Size dataSize); virtual bool deserialize(QDataStream& stream, SyncProtocol::tPayload Size dataSize);
//! Subclasses can override this to provide proper debug output.
//! The default just prints the message type.
virtual QDebug debugOutput(QDebug dbg) const
{
return dbg;
}
friend QDebug operator<<(QDebug dbg, const SyncMessage& msg)
{
dbg = dbg<<msg.getMessageType()<<'[';
dbg = msg.debugOutput(dbg);
return dbg<<']';
}
protected: protected:
static void writeString(QDataStream& stream, const QString& str); static void writeString(QDataStream& stream, const QString& str);
static QString readString(QDataStream& stream); static QString readString(QDataStream& stream);
}; };
}
class SyncMessageHandler; class SyncMessageHandler;
//! Handling the connection to a remote peer (i.e. all clients on the serve r, and the server on the client) //! Handling the connection to a remote peer (i.e. all clients on the serve r, and the server on the client)
class SyncRemotePeer class SyncRemotePeer : public QObject
{ {
Q_OBJECT
public: public:
SyncRemotePeer();
SyncRemotePeer(QAbstractSocket* socket, bool isServer, const QVector <SyncMessageHandler*>& handlerList); SyncRemotePeer(QAbstractSocket* socket, bool isServer, const QVector <SyncMessageHandler*>& handlerList);
~SyncRemotePeer();
//! Call this to try to receive message data from the socket.
//! If a fully formed message is currently buffered, it is processed
.
void receiveMessage();
//! Sends a message to this peer //! Sends a message to this peer
void writeMessage(const SyncMessage& msg); void writeMessage(const SyncProtocol::SyncMessage& msg);
//! Writes this data packet to the socket without processing //! Writes this data packet to the socket without processing
void writeData(const QByteArray& data, int size=-1); void writeData(const QByteArray& data, int size=-1);
//! Can be used to write an error message to the peer and drop the c onnection //! Can be used to write an error message to the peer and drop the c onnection
void writeError(const QString& err); void writeError(const QString& err);
//! Log a message for this peer //! Log a message for this peer
void peerLog(const QString& msg); void peerLog(const QString& msg) const;
QDebug peerLog() const;
bool isAuthenticated() const { return authenticated; }
QUuid getID() const { return id; }
void checkTimeout();
void disconnectPeer();
bool isValid; QString getError() const { return errorString; }
signals:
void disconnected(bool cleanDisconnect);
private slots:
void sockDisconnected();
void sockError(QAbstractSocket::SocketError err);
void sockStateChanged(QAbstractSocket::SocketState state);
//! Call this to try to read message data from the socket.
//! If a fully formed message is currently buffered, it is processed
.
void receiveMessage();
private:
QAbstractSocket* sock; // The socket for communication with this pee r QAbstractSocket* sock; // The socket for communication with this pee r
QDataStream stream;
QString errorString;
bool expectDisconnect;
bool isPeerAServer; // True if this identifies a server bool isPeerAServer; // True if this identifies a server
QUuid id; // An ID value, currently not used for anything else than auth. The server always has a NULL UUID. QUuid id; // An ID value, currently not used for anything else than auth. The server always has a NULL UUID.
bool isAuthenticated; // True if the peer ran through the HELLO proc ess and can receive/send all message types bool authenticated; // True if the peer ran through the HELLO proces s and can receive/send all message types
bool authResponseSent; //only for client use, tracks if the client h as sent a resonse to the server challenge bool authResponseSent; //only for client use, tracks if the client h as sent a resonse to the server challenge
bool waitingForBody; //True if waiting for full message body (after header was received) bool waitingForBody; //True if waiting for full message body (after header was received)
SyncProtocol::SyncHeader msgHeader; //the last message header read/c urrently being processed SyncProtocol::SyncHeader msgHeader; //the last message header read/c urrently being processed
qint64 lastReceiveTime; // The time the last data of this peer was r eceived qint64 lastReceiveTime; // The time the last data of this peer was r eceived
qint64 lastSendTime; //The time the last data was written to this pe er qint64 lastSendTime; //The time the last data was written to this pe er
QVector<SyncMessageHandler*> handlerList; QVector<SyncMessageHandler*> handlerList;
QByteArray msgWriteBuffer; //Byte array used to construct messages b efore writing them QByteArray msgWriteBuffer; //Byte array used to construct messages b efore writing them
friend class ServerAuthHandler;
friend class ClientAuthHandler;
}; };
//! Base interface for message handlers, i.e. reacting to messages //! Base interface for message handlers, i.e. reacting to messages
class SyncMessageHandler class SyncMessageHandler
{ {
public: public:
virtual ~SyncMessageHandler() {} virtual ~SyncMessageHandler() {}
//! Read a message directly from the stream. SyncMessage::deserializ e of the correct class should be used to deserialize the message. //! Read a message directly from the stream. SyncMessage::deserializ e of the correct class should be used to deserialize the message.
//! @param stream The stream to be used to read data. The current po
sition is after the header.
//! @param dataSize The data size from the message header
//! @param peer The remote peer this message originated from. Can be used to send replies through SyncRemotePeer::writeMessage //! @param peer The remote peer this message originated from. Can be used to send replies through SyncRemotePeer::writeMessage
//! @return return false if the message is found to be invalid. The connection to the client/server will be dropped. //! @return return false if the message is found to be invalid. The connection to the client/server will be dropped.
virtual bool handleMessage(QDataStream& stream, SyncRemotePeer& peer virtual bool handleMessage(QDataStream& stream, SyncProtocol::tPaylo
) = 0; adSize dataSize, SyncRemotePeer& peer) = 0;
};
//! Skips the message, and does nothing else.
class DummyMessageHandler : public SyncMessageHandler
{
public:
virtual bool handleMessage(QDataStream &stream, SyncProtocol::tPaylo
adSize dataSize, SyncRemotePeer &peer)
{
stream.skipRawData(dataSize);
return !stream.status();
}
}; };
Q_DECLARE_INTERFACE(SyncMessageHandler,"Stellarium/RemoteSync/SyncMessageHa ndler/1.0") Q_DECLARE_INTERFACE(SyncMessageHandler,"Stellarium/RemoteSync/SyncMessageHa ndler/1.0")
#endif #endif
 End of changes. 21 change blocks. 
21 lines changed or deleted 81 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/