X-Plane Remote Access Plugin and Client Library
ServerThread.cc
1 // Copyright (c) 2013 by István Váradi
2 
3 // This file is part of XPLRA, a remote-access plugin for X-Plane
4 
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 
8 // 1. Redistributions of source code must retain the above copyright notice, this
9 // list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 
14 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 
25 // The views and conclusions contained in the software and documentation are those
26 // of the authors and should not be interpreted as representing official policies,
27 // either expressed or implied, of the FreeBSD Project.
28 
29 //------------------------------------------------------------------------------
30 
31 #include "ServerThread.h"
32 
33 #include "ListenThread.h"
34 #include "RequestQueue.h"
35 #include "Protocol.h"
36 #include "GetDataRefTask.h"
37 #include "SetDataRefTask.h"
38 #include "TaskRequest.h"
39 #include "GetMultiDataRefRequest.h"
40 #include "SetMultiDataRefRequest.h"
41 #include "ReloadPluginsRequest.h"
42 #ifdef XPLM200
43 #include "SaveSituationRequest.h"
44 #endif
45 #include "MessageRequest.h"
46 #include "Globals.h"
47 
48 #include <hu/varadiistvan/xplcommon/Util.h>
49 
50 #include <cstdio>
51 
52 //------------------------------------------------------------------------------
53 
55 
56 using hu::varadiistvan::scpl::io::BufferedStreamAcceptor;
57 using hu::varadiistvan::scpl::Mutex;
58 using hu::varadiistvan::xplcommon::Util;
59 
60 using std::string;
61 
62 //------------------------------------------------------------------------------
63 
64 Mutex ServerThread::instancesMutex;
65 
66 ServerThread::instances_t ServerThread::instances;
67 
68 //------------------------------------------------------------------------------
69 
70 void ServerThread::quitAll()
71 {
72  instancesMutex.lock();
73  for(instances_t::iterator i = instances.begin(); i!=instances.end(); ++i) {
74  ServerThread* thread = *i;
75  thread->quit();
76  thread->join();
77  delete thread;
78  }
79  instances.clear();
80  instancesMutex.unlock();
81 }
82 
83 //------------------------------------------------------------------------------
84 
86 {
87  if (hotkeys!=0) {
89  delete hotkeys; hotkeys = 0;
90  return true;
91  } else {
92  return false;
93  }
94 }
95 
96 //------------------------------------------------------------------------------
97 
99  RequestQueue& requestQueue,
100  BufferedStreamAcceptor& acceptor) :
101  listenThread(listenThread),
102  requestQueue(requestQueue),
103  bufferedStream(acceptor.getAcceptedBufferedStream(&waiter)),
104  stream(*bufferedStream),
105  nextGetMultiRequestID(1),
106  nextSetMultiRequestID(1),
107  hotkeys(0)
108 {
109  instancesMutex.lock();
110  instances.insert(this);
111  instancesMutex.unlock();
112 }
113 
114 //------------------------------------------------------------------------------
115 
117 {
118  delete bufferedStream;
119 
120  for(getMultiRequests_t::iterator i = getMultiRequests.begin();
121  i!=getMultiRequests.end(); ++i)
122  {
123  delete i->second;
124  }
125 
126  for(setMultiRequests_t::iterator i = setMultiRequests.begin();
127  i!=setMultiRequests.end(); ++i)
128  {
129  delete i->second;
130  }
131 }
132 
133 //------------------------------------------------------------------------------
134 
136 {
137  stream.interrupt();
138 }
139 
140 //------------------------------------------------------------------------------
141 
143 {
144  Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run\n", this);
145  while(stream) {
146  uint8_t command = stream.readU8();
147  if (!stream) continue;
148 
149  // Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run: command=0x%02x\n",
150  // this, command);
151 
152  if (command==Protocol::COMMAND_GET_SINGLE) {
153  if (!handleGetSingle()) break;
154  } else if (command==Protocol::COMMAND_SET_SINGLE) {
155  if (!handleSetSingle()) break;
156  } else if (command==Protocol::COMMAND_GET_MULTI) {
157  if (!handleGetMulti()) break;
158  } else if (command==Protocol::COMMAND_SET_MULTI) {
159  if (!handleSetMulti()) break;
160  } else if (command==Protocol::COMMAND_REGISTER_GET_MULTI) {
161  if (!handleRegisterGetMulti()) break;
162  } else if (command==Protocol::COMMAND_UNREGISTER_GET_MULTI) {
163  if (!handleUnregisterGetMulti()) break;
164  } else if (command==Protocol::COMMAND_EXECUTE_GET_MULTI) {
165  if (!handleExecuteGetMulti()) break;
166  } else if (command==Protocol::COMMAND_REGISTER_SET_MULTI) {
167  if (!handleRegisterSetMulti()) break;
168  } else if (command==Protocol::COMMAND_UNREGISTER_SET_MULTI) {
169  if (!handleUnregisterSetMulti()) break;
170  } else if (command==Protocol::COMMAND_EXECUTE_SET_MULTI) {
171  if (!handleExecuteSetMulti()) break;
172  } else if (command==Protocol::COMMAND_GET_VERSIONS) {
173  if (!handleGetVersions()) break;
174  } else if (command==Protocol::COMMAND_RELOAD_PLUGINS) {
175  if (!handleReloadPlugins()) break;
176 #ifdef XPLM200
177  } else if (command==Protocol::COMMAND_SAVE_SITUATION) {
178  if (!handleSaveSituation()) break;
179 #endif
180  } else if (command==Protocol::COMMAND_SHOW_MESSAGE) {
181  if (!handleShowMessage()) break;
182  } else if (command==Protocol::COMMAND_REGISTER_HOTKEYS) {
183  if (!handleRegisterHotkeys()) break;
184  } else if (command==Protocol::COMMAND_QUERY_HOTKEYS) {
185  if (!handleQueryHotkeys()) break;
186  } else if (command==Protocol::COMMAND_UNREGISTER_HOTKEYS) {
187  if (!handleUnregisterHotkeys()) break;
188  } else {
190  }
191  stream.flush();
192  }
193 
194  destroyHotkeys();
195 
196  Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run: quitting\n", this);
197 }
198 
199 //------------------------------------------------------------------------------
200 
202 {
203  uint8_t result = Protocol::RESULT_OK;
205 
206  if (!stream) {
207  return false;
208  } else if (task==0) {
209  stream.writeU8(result);
210  return true;
211  }
212 
213  TaskRequest request(task);
214  if (!requestQueue.execute(&request)) return false;
215 
216  if (task->isValid()) {
217  stream.writeU8(Protocol::RESULT_OK);
218  task->writeValue(stream);
219  } else {
221  }
222 
223  return true;
224 }
225 
226 //------------------------------------------------------------------------------
227 
229 {
230  uint8_t result = Protocol::RESULT_OK;
232 
233  if (!stream) {
234  return false;
235  } else if (task==0) {
236  stream.writeU8(result);
237  return true;
238  }
239 
240  task->readValue(stream);
241  if (!stream) {
242  delete task;
243  return false;
244  }
245 
246  TaskRequest request(task);
247  if (!requestQueue.execute(&request)) return false;
248 
249  stream.writeU8(task->isValid() ? Protocol::RESULT_OK :
251  return true;
252 }
253 
254 //------------------------------------------------------------------------------
255 
257 {
258  uint8_t result = Protocol::RESULT_OK;
259  GetMultiDataRefRequest* request =
260  new GetMultiDataRefRequest(result, stream);
261  if (result!=Protocol::RESULT_OK || !stream) {
262  delete request;
263  stream.writeU8(result);
264  return stream;
265  }
266 
267  bool isOK = requestQueue.execute(request);
268 
269  if (isOK) {
270  request->writeResult(stream);
271  }
272 
273  delete request;
274 
275  return isOK;
276 }
277 
278 //------------------------------------------------------------------------------
279 
281 {
282  uint8_t result = Protocol::RESULT_OK;
283  SetMultiDataRefRequest* request =
284  new SetMultiDataRefRequest(result, stream, true);
285  if (result!=Protocol::RESULT_OK || !stream) {
286  delete request;
287  stream.writeU8(result);
288  return stream;
289  }
290 
291  bool isOK = requestQueue.execute(request);
292 
293  if (isOK) {
294  request->writeResult(stream);
295  }
296 
297  delete request;
298 
299  return isOK;
300 }
301 
302 //------------------------------------------------------------------------------
303 
305 {
306  uint8_t result = Protocol::RESULT_OK;
307  GetMultiDataRefRequest* request =
308  new GetMultiDataRefRequest(result, stream);
309  if (result!=Protocol::RESULT_OK || !stream) {
310  delete request;
311  stream.writeU8(result);
312  return stream;
313  }
314 
315  size_t id = nextGetMultiRequestID++;
316  getMultiRequests[id] = request;
317 
318  stream.writeU8(Protocol::RESULT_OK);
319  stream.writeU32(id);
320 
321  return true;
322 }
323 
324 //------------------------------------------------------------------------------
325 
327 {
328  uint32_t id = stream.readU32();
329  if (!stream) return false;
330 
331  getMultiRequests_t::iterator i = getMultiRequests.find(id);
332  if (i==getMultiRequests.end()) {
334  } else {
335  GetMultiDataRefRequest* request = i->second;
336  getMultiRequests.erase(i);
337  delete request;
338  stream.writeU8(Protocol::RESULT_OK);
339  }
340 
341  return true;
342 }
343 
344 //------------------------------------------------------------------------------
345 
347 {
348  uint32_t id = stream.readU32();
349  if (!stream) return false;
350 
351  getMultiRequests_t::iterator i = getMultiRequests.find(id);
352  if (i==getMultiRequests.end()) {
354  } else {
355  GetMultiDataRefRequest* request = i->second;
356  if (!requestQueue.execute(request)) return false;
357  request->writeResult(stream);
358  }
359 
360  return true;
361 }
362 
363 //------------------------------------------------------------------------------
364 
366 {
367  uint8_t result = Protocol::RESULT_OK;
368  SetMultiDataRefRequest* request =
369  new SetMultiDataRefRequest(result, stream, false);
370  if (result!=Protocol::RESULT_OK || !stream) {
371  delete request;
372  stream.writeU8(result);
373  return stream;
374  }
375 
376  size_t id = nextSetMultiRequestID++;
377  setMultiRequests[id] = request;
378 
379  stream.writeU8(Protocol::RESULT_OK);
380  stream.writeU32(id);
381 
382  return true;
383 }
384 
385 //------------------------------------------------------------------------------
386 
388 {
389  uint32_t id = stream.readU32();
390  if (!stream) return false;
391 
392  setMultiRequests_t::iterator i = setMultiRequests.find(id);
393  if (i==setMultiRequests.end()) {
395  } else {
396  SetMultiDataRefRequest* request = i->second;
397  setMultiRequests.erase(i);
398  delete request;
399  stream.writeU8(Protocol::RESULT_OK);
400  }
401 
402  return true;
403 }
404 
405 //------------------------------------------------------------------------------
406 
408 {
409  uint32_t id = stream.readU32();
410  if (!stream) return false;
411 
412  setMultiRequests_t::iterator i = setMultiRequests.find(id);
413  if (i==setMultiRequests.end()) {
415  } else {
416  SetMultiDataRefRequest* request = i->second;
417  request->readValues(stream);
418  if (!stream || !requestQueue.execute(request)) return false;
419  request->writeResult(stream);
420  }
421 
422  return true;
423 }
424 
425 //------------------------------------------------------------------------------
426 
428 {
429  int xplaneVersion = 0;
430  int xplmVersion = 0;
431 
432  listenThread.getGlobals().getVersions(xplaneVersion, xplmVersion);
433 
434  stream.writeU8(Protocol::RESULT_OK);
435  stream.writeS32(xplaneVersion);
436  stream.writeS32(xplmVersion);
437  stream.writeS32(Protocol::version);
438 
439  return true;
440 }
441 
442 //------------------------------------------------------------------------------
443 
445 {
446  ReloadPluginsRequest request;
447  if (!requestQueue.execute(&request)) return false;
448 
449  stream.writeU8(Protocol::RESULT_OK);
450 
451  return true;
452 }
453 
454 //------------------------------------------------------------------------------
455 
456 #ifdef XPLM200
457 
458 bool ServerThread::handleSaveSituation()
459 {
460  string path = stream.readString();
461  SaveSituationRequest request(path);
462  if (!requestQueue.execute(&request)) return false;
463 
464  stream.writeU8(request.getSuccess() ? Protocol::RESULT_OK :
466 
467  return true;
468 }
469 
470 #endif
471 
472 //------------------------------------------------------------------------------
473 
475 {
476  string message = stream.readString();
477  float duration = stream.readFloat();
478  if (!stream) return false;
479 
480  if (duration>Protocol::MAX_MESSAGE_DURATION) {
482  } else {
484  message, duration);
485  if (!requestQueue.execute(&request)) return false;
486 
487  stream.writeU8(Protocol::RESULT_OK);
488  }
489 
490  return true;
491 }
492 
493 //------------------------------------------------------------------------------
494 
496 {
497  size_t numHotkeys = stream.readU32();
498  if (!stream) return false;
499 
500  if (numHotkeys>Protocol::MAX_HOTKEY_COUNT) {
502  } else {
503  HotkeyHandler::Hotkeys* newHotkeys =
504  new HotkeyHandler::Hotkeys(numHotkeys, stream);
505  if (newHotkeys->isValid()) {
506  destroyHotkeys();
507  hotkeys = newHotkeys;
509  stream.writeU8(Protocol::RESULT_OK);
510  } else {
511  delete newHotkeys;
512  return false;
513  }
514  }
515 
516  return true;
517 }
518 
519 //------------------------------------------------------------------------------
520 
522 {
523  stream.writeU8(Protocol::RESULT_OK);
524  if (hotkeys==0) {
525  stream.writeU32(0);
526  } else {
528  }
529  return true;
530 }
531 
532 //------------------------------------------------------------------------------
533 
535 {
536  destroyHotkeys();
537  stream.writeU8(Protocol::RESULT_OK);
538  return true;
539 }
540 
541 //------------------------------------------------------------------------------
542 
543 // Local Variables:
544 // mode: C++
545 // c-basic-offset: 4
546 // indent-tabs-mode: nil
547 // End:
bool isValid() const
Definition: DataRefTask.h:125
virtual void writeValue(hu::varadiistvan::scpl::io::DataStream &stream)=0
static GetDataRefTask * create(uint8_t &result, hu::varadiistvan::scpl::io::DataStream &stream)
void writeResult(hu::varadiistvan::scpl::io::DataStream &stream) const
void getVersions(int &xplaneV, int &xplmV) const
Definition: Globals.h:101
MessageWindow & getMessageWindow()
Definition: Globals.h:109
HotkeyHandler & getHotkeyHandler()
Definition: Globals.h:116
void writePressed(hu::varadiistvan::scpl::io::DataStream &stream)
void unregisterHotkeys(Hotkeys *hotkeys)
void registerHotkeys(Hotkeys *hotkeys)
Globals & getGlobals()
Definition: ListenThread.h:120
static const int version
Definition: Protocol.h:277
static const uint8_t COMMAND_UNREGISTER_GET_MULTI
Definition: Protocol.h:76
static const uint8_t COMMAND_EXECUTE_GET_MULTI
Definition: Protocol.h:81
static const uint8_t COMMAND_REGISTER_GET_MULTI
Definition: Protocol.h:71
static const uint8_t RESULT_INVALID_LENGTH
Definition: Protocol.h:215
static const uint8_t COMMAND_QUERY_HOTKEYS
Definition: Protocol.h:153
static const uint8_t RESULT_OK
Definition: Protocol.h:195
static const uint8_t COMMAND_SET_SINGLE
Definition: Protocol.h:56
static constexpr float MAX_MESSAGE_DURATION
Definition: Protocol.h:266
static const uint8_t COMMAND_REGISTER_HOTKEYS
Definition: Protocol.h:136
static const uint8_t COMMAND_GET_SINGLE
Definition: Protocol.h:51
static const uint8_t COMMAND_SET_MULTI
Definition: Protocol.h:66
static const uint8_t COMMAND_UNREGISTER_HOTKEYS
Definition: Protocol.h:160
static const uint8_t RESULT_OTHER_ERROR
Definition: Protocol.h:240
static const uint8_t COMMAND_REGISTER_SET_MULTI
Definition: Protocol.h:86
static const uint8_t RESULT_INVALID_COMMAND
Definition: Protocol.h:200
static const uint8_t RESULT_INVALID_ID
Definition: Protocol.h:230
static const uint8_t RESULT_UNKNOWN_DATAREF
Definition: Protocol.h:205
static const uint8_t COMMAND_GET_MULTI
Definition: Protocol.h:61
static const uint8_t COMMAND_GET_VERSIONS
Definition: Protocol.h:101
static const uint8_t COMMAND_UNREGISTER_SET_MULTI
Definition: Protocol.h:91
static const uint8_t COMMAND_SHOW_MESSAGE
Definition: Protocol.h:119
static const uint8_t COMMAND_EXECUTE_SET_MULTI
Definition: Protocol.h:96
static const size_t MAX_HOTKEY_COUNT
Definition: Protocol.h:272
static const uint8_t COMMAND_SAVE_SITUATION
Definition: Protocol.h:114
static const uint8_t COMMAND_RELOAD_PLUGINS
Definition: Protocol.h:106
static const uint8_t RESULT_INVALID_DURATION
Definition: Protocol.h:235
bool execute(Request *request)
Definition: RequestQueue.cc:79
ServerThread(ListenThread &listenThread, RequestQueue &requestQueue, hu::varadiistvan::scpl::io::BufferedStreamAcceptor &acceptor)
Definition: ServerThread.cc:98
setMultiRequests_t setMultiRequests
Definition: ServerThread.h:143
static instances_t instances
Definition: ServerThread.h:91
HotkeyHandler::Hotkeys * hotkeys
Definition: ServerThread.h:148
bool handleUnregisterSetMulti()
ListenThread & listenThread
Definition: ServerThread.h:103
static hu::varadiistvan::scpl::Mutex instancesMutex
Definition: ServerThread.h:86
RequestQueue & requestQueue
Definition: ServerThread.h:108
size_t nextSetMultiRequestID
Definition: ServerThread.h:138
hu::varadiistvan::scpl::io::BufferedStream * bufferedStream
Definition: ServerThread.h:118
bool handleUnregisterHotkeys()
virtual void run()
size_t nextGetMultiRequestID
Definition: ServerThread.h:128
bool handleUnregisterGetMulti()
hu::varadiistvan::scpl::io::DataStream stream
Definition: ServerThread.h:123
getMultiRequests_t getMultiRequests
Definition: ServerThread.h:133
static SetDataRefTask * create(uint8_t &result, hu::varadiistvan::scpl::io::DataStream &stream)
virtual void readValue(hu::varadiistvan::scpl::io::DataStream &stream)=0
void readValues(hu::varadiistvan::scpl::io::DataStream &stream)
void writeResult(hu::varadiistvan::scpl::io::DataStream &stream) const