Stellarium  0.16.1
SyncProtocol.hpp
1 /*
2  * Stellarium Remote Sync plugin
3  * Copyright (C) 2015 Florian Schaukowitsch
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  */
19 
20 #ifndef SYNCPROTOCOL_HPP_
21 #define SYNCPROTOCOL_HPP_
22 
23 #include <QByteArray>
24 #include <QDataStream>
25 #include <QAbstractSocket>
26 #include <QUuid>
27 
29 namespace SyncProtocol
30 {
31 
32 //Important: All data should use the sized typedefs provided by Qt (i.e. qint32 instead of 4 byte int on x86)
33 
35 const quint8 SYNC_PROTOCOL_VERSION = 2;
36 const QDataStream::Version SYNC_DATASTREAM_VERSION = QDataStream::Qt_5_0;
38 const QByteArray SYNC_MAGIC_VALUE = "StellariumSyncPluginProtocol";
39 
40 typedef quint16 tPayloadSize;
41 
43 struct SyncHeader
44 {
45  quint8 msgType; //The SyncMessageType of the data
46  SyncProtocol::tPayloadSize dataSize; //The size of the data part
47 };
48 
50 QDataStream& operator<<(QDataStream& out, const SyncHeader& header);
52 QDataStream& operator>>(QDataStream& in, SyncHeader& header);
53 
54 const qint64 SYNC_HEADER_SIZE = sizeof(quint8) + sizeof(tPayloadSize); //3 byte
55 const qint64 SYNC_MAX_PAYLOAD_SIZE = (2<<15) - 1; // 65535
56 const qint64 SYNC_MAX_MESSAGE_SIZE = SYNC_HEADER_SIZE + SYNC_MAX_PAYLOAD_SIZE;
57 
61 {
62  ERROR, //sent to the other party on protocol/auth error with a message, connection will be dropped afterwards
63  SERVER_CHALLENGE, //sent as a challenge to the client on establishment of connection
64  CLIENT_CHALLENGE_RESPONSE, //sent as a reply to the challenge
65  SERVER_CHALLENGERESPONSEVALID, //sent from the server to the client after valid client hello was received.
66  ALIVE, //sent from a peer after no data was sent for about 5 seconds to indicate it is still alive
67 
68  //all messages below here can only be sent from authenticated peers
69  TIME, //time jumps + time scale updates
70  LOCATION, //location changes
71  SELECTION, //current selection changed
72  STELPROPERTY, //stelproperty updates
73  VIEW, //view change
74  FOV, //fov change
75 
76  MSGTYPE_MAX = FOV,
77  MSGTYPE_SIZE = MSGTYPE_MAX+1
78 };
79 
80 inline QDebug& operator<<(QDebug& deb, SyncMessageType msg)
81 {
82  switch (msg) {
83  case SyncProtocol::ERROR:
84  deb<<"ERROR";
85  break;
86  case SyncProtocol::SERVER_CHALLENGE:
87  deb<<"SERVER_CHALLENGE";
88  break;
89  case SyncProtocol::CLIENT_CHALLENGE_RESPONSE:
90  deb<<"CLIENT_CHALLENGE_RESPONSE";
91  break;
92  case SyncProtocol::SERVER_CHALLENGERESPONSEVALID:
93  deb<<"SERVER_CHALLENGERESPONSEVALID";
94  break;
95  case SyncProtocol::TIME:
96  deb<<"TIME";
97  break;
98  case SyncProtocol::LOCATION:
99  deb<<"LOCATION";
100  break;
101  case SyncProtocol::SELECTION:
102  deb<<"SELECTION";
103  break;
104  case SyncProtocol::STELPROPERTY:
105  deb<<"STELPROPERTY";
106  break;
107  case SyncProtocol::VIEW:
108  deb<<"VIEW";
109  break;
110  case SyncProtocol::FOV:
111  deb<<"FOV";
112  break;
113  case SyncProtocol::ALIVE:
114  deb<<"ALIVE";
115  break;
116  default:
117  deb<<"UNKNOWN("<<int(msg)<<')';
118  break;
119  }
120  return deb;
121 }
122 
125 {
126 public:
127  virtual ~SyncMessage() {}
128 
130  virtual SyncProtocol::SyncMessageType getMessageType() const = 0;
131 
134  qint64 createFullMessage(QByteArray& target) const;
135 
138  virtual void serialize(QDataStream& stream) const;
141  virtual bool deserialize(QDataStream& stream, SyncProtocol::tPayloadSize dataSize);
142 
145  virtual QDebug debugOutput(QDebug dbg) const
146  {
147  return dbg;
148  }
149 
150  friend QDebug operator<<(QDebug dbg, const SyncMessage& msg)
151  {
152  dbg = dbg<<msg.getMessageType()<<'[';
153  dbg = msg.debugOutput(dbg);
154  return dbg<<']';
155  }
156 
157 protected:
158  static void writeString(QDataStream& stream, const QString& str);
159  static QString readString(QDataStream& stream);
160 };
161 
162 }
163 
164 class SyncMessageHandler;
165 
167 class SyncRemotePeer : public QObject
168 {
169  Q_OBJECT
170 public:
171  SyncRemotePeer(QAbstractSocket* socket, bool isServer, const QVector<SyncMessageHandler*>& handlerList);
172  ~SyncRemotePeer();
173 
174 
175 
177  void writeMessage(const SyncProtocol::SyncMessage& msg);
179  void writeData(const QByteArray& data, int size=-1);
181  void writeError(const QString& err);
182 
184  void peerLog(const QString& msg) const;
185  QDebug peerLog() const;
186 
187  bool isAuthenticated() const { return authenticated; }
188  QUuid getID() const { return id; }
189 
190  void checkTimeout();
191  void disconnectPeer();
192 
193  QString getError() const { return errorString; }
194 signals:
195  void disconnected(bool cleanDisconnect);
196 private slots:
197  void sockDisconnected();
198  void sockError(QAbstractSocket::SocketError err);
199  void sockStateChanged(QAbstractSocket::SocketState state);
200 
203  void receiveMessage();
204 private:
205  QAbstractSocket* sock; // The socket for communication with this peer
206  QDataStream stream;
207  QString errorString;
208  bool expectDisconnect;
209  bool isPeerAServer; // True if this identifies a server
210  QUuid id; // An ID value, currently not used for anything else than auth. The server always has a NULL UUID.
211  bool authenticated; // True if the peer ran through the HELLO process and can receive/send all message types
212  bool authResponseSent; //only for client use, tracks if the client has sent a resonse to the server challenge
213  bool waitingForBody; //True if waiting for full message body (after header was received)
214  SyncProtocol::SyncHeader msgHeader; //the last message header read/currently being processed
215  qint64 lastReceiveTime; // The time the last data of this peer was received
216  qint64 lastSendTime; //The time the last data was written to this peer
217  QVector<SyncMessageHandler*> handlerList;
218  QByteArray msgWriteBuffer; //Byte array used to construct messages before writing them
219 
220  friend class ServerAuthHandler;
221  friend class ClientAuthHandler;
222 };
223 
226 {
227 public:
228  virtual ~SyncMessageHandler() {}
229 
235  virtual bool handleMessage(QDataStream& stream, SyncProtocol::tPayloadSize dataSize, SyncRemotePeer& peer) = 0;
236 };
237 
240 {
241 public:
242  virtual bool handleMessage(QDataStream &stream, SyncProtocol::tPayloadSize dataSize, SyncRemotePeer &peer)
243  {
244  stream.skipRawData(dataSize);
245  return !stream.status();
246  }
247 };
248 
249 Q_DECLARE_INTERFACE(SyncMessageHandler,"Stellarium/RemoteSync/SyncMessageHandler/1.0")
250 
251 
252 #endif
All messages are preceded by this.
Main class of the Field of View plugin.
Definition: FOV.hpp:47
Base interface for message handlers, i.e. reacting to messages.
Base interface for the messages themselves, allowing to serialize/deserialize them.
Contains sync protocol data definitions shared between client and server.
Server-side auth handler.
Reacts to Server challenge and challenge OK on the client.
Handling the connection to a remote peer (i.e. all clients on the server, and the server on the clien...
QDataStream & operator>>(QDataStream &in, SyncHeader &header)
Read a SyncHeader from a DataStream.
virtual SyncProtocol::SyncMessageType getMessageType() const =0
Subclasses must return the message type this message represents.
Skips the message, and does nothing else.
SyncMessageType
Contains the possible message types.
const QByteArray SYNC_MAGIC_VALUE
Magic value for protocol used during connection. Should NEVER change.
virtual QDebug debugOutput(QDebug dbg) const
Subclasses can override this to provide proper debug output.
const quint8 SYNC_PROTOCOL_VERSION
Should be changed with every breaking change.
virtual bool handleMessage(QDataStream &stream, SyncProtocol::tPayloadSize dataSize, SyncRemotePeer &peer)
Read a message directly from the stream.
QDataStream & operator<<(QDataStream &out, const SyncHeader &header)
Write a SyncHeader to a DataStream.