source: xplra/src/plugin/src/xplra/ServerThread.cc@ 104:a41f04cda4c2

Last change on this file since 104:a41f04cda4c2 was 104:a41f04cda4c2, checked in by István Váradi <ivaradi@…>, 17 months ago

The plugin accepts connections over TCP as well

File size: 15.6 KB
Line 
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
54using xplra::ServerThread;
55
56using hu::varadiistvan::scpl::io::BufferedStreamAcceptor;
57using hu::varadiistvan::scpl::Mutex;
58using hu::varadiistvan::xplcommon::Util;
59
60using std::string;
61
62//------------------------------------------------------------------------------
63
64Mutex ServerThread::instancesMutex;
65
66ServerThread::instances_t ServerThread::instances;
67
68//------------------------------------------------------------------------------
69
70void 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
85inline bool ServerThread::destroyHotkeys()
86{
87 if (hotkeys!=0) {
88 listenThread.getGlobals().getHotkeyHandler().unregisterHotkeys(hotkeys);
89 delete hotkeys; hotkeys = 0;
90 return true;
91 } else {
92 return false;
93 }
94}
95
96//------------------------------------------------------------------------------
97
98ServerThread::ServerThread(ListenThread& listenThread,
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
116ServerThread::~ServerThread()
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
135void ServerThread::quit()
136{
137 stream.interrupt();
138}
139
140//------------------------------------------------------------------------------
141
142void ServerThread::run()
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 {
189 stream.writeU8(Protocol::RESULT_INVALID_COMMAND);
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
201bool ServerThread::handleGetSingle()
202{
203 uint8_t result = Protocol::RESULT_OK;
204 GetDataRefTask* task = GetDataRefTask::create(result, stream);
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 {
220 stream.writeU8(Protocol::RESULT_UNKNOWN_DATAREF);
221 }
222
223 return true;
224}
225
226//------------------------------------------------------------------------------
227
228bool ServerThread::handleSetSingle()
229{
230 uint8_t result = Protocol::RESULT_OK;
231 SetDataRefTask* task = SetDataRefTask::create(result, stream);
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 :
250 Protocol::RESULT_UNKNOWN_DATAREF);
251 return true;
252}
253
254//------------------------------------------------------------------------------
255
256bool ServerThread::handleGetMulti()
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
280bool ServerThread::handleSetMulti()
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
304bool ServerThread::handleRegisterGetMulti()
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
326bool ServerThread::handleUnregisterGetMulti()
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()) {
333 stream.writeU8(Protocol::RESULT_INVALID_ID);
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
346bool ServerThread::handleExecuteGetMulti()
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()) {
353 stream.writeU8(Protocol::RESULT_INVALID_ID);
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
365bool ServerThread::handleRegisterSetMulti()
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
387bool ServerThread::handleUnregisterSetMulti()
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()) {
394 stream.writeU8(Protocol::RESULT_INVALID_ID);
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
407bool ServerThread::handleExecuteSetMulti()
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()) {
414 stream.writeU8(Protocol::RESULT_INVALID_ID);
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
427bool ServerThread::handleGetVersions()
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
444bool ServerThread::handleReloadPlugins()
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
458bool 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 :
465 Protocol::RESULT_OTHER_ERROR);
466
467 return true;
468}
469
470#endif
471
472//------------------------------------------------------------------------------
473
474bool ServerThread::handleShowMessage()
475{
476 string message = stream.readString();
477 float duration = stream.readFloat();
478 if (!stream) return false;
479
480 if (duration>Protocol::MAX_MESSAGE_DURATION) {
481 stream.writeU8(Protocol::RESULT_INVALID_DURATION);
482 } else {
483 MessageRequest request(listenThread.getGlobals().getMessageWindow(),
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
495bool ServerThread::handleRegisterHotkeys()
496{
497 size_t numHotkeys = stream.readU32();
498 if (!stream) return false;
499
500 if (numHotkeys>Protocol::MAX_HOTKEY_COUNT) {
501 stream.writeU8(Protocol::RESULT_INVALID_LENGTH);
502 } else {
503 HotkeyHandler::Hotkeys* newHotkeys =
504 new HotkeyHandler::Hotkeys(numHotkeys, stream);
505 if (newHotkeys->isValid()) {
506 destroyHotkeys();
507 hotkeys = newHotkeys;
508 listenThread.getGlobals().getHotkeyHandler().registerHotkeys(hotkeys);
509 stream.writeU8(Protocol::RESULT_OK);
510 } else {
511 delete newHotkeys;
512 return false;
513 }
514 }
515
516 return true;
517}
518
519//------------------------------------------------------------------------------
520
521bool ServerThread::handleQueryHotkeys()
522{
523 stream.writeU8(Protocol::RESULT_OK);
524 if (hotkeys==0) {
525 stream.writeU32(0);
526 } else {
527 hotkeys->writePressed(stream);
528 }
529 return true;
530}
531
532//------------------------------------------------------------------------------
533
534bool ServerThread::handleUnregisterHotkeys()
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:
Note: See TracBrowser for help on using the repository browser.