source: xplra/src/plugin/src/xplra/ServerThread.cc@ 45:72d5105fcb72

Last change on this file since 45:72d5105fcb72 was 45:72d5105fcb72, checked in by István Váradi <ivaradi@…>, 11 years ago

Implemented hotkey handling

File size: 14.9 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#include "MessageRequest.h"
43#include "Globals.h"
44
45#include <hu/varadiistvan/xplcommon/Util.h>
46
47#include <cstdio>
48
49//------------------------------------------------------------------------------
50
51using xplra::ServerThread;
52
53using hu::varadiistvan::scpl::io::LocalAcceptor;
54using hu::varadiistvan::scpl::Mutex;
55using hu::varadiistvan::xplcommon::Util;
56
57using std::string;
58
59//------------------------------------------------------------------------------
60
61Mutex ServerThread::instancesMutex;
62
63ServerThread::instances_t ServerThread::instances;
64
65//------------------------------------------------------------------------------
66
67void ServerThread::quitAll()
68{
69 instancesMutex.lock();
70 for(instances_t::iterator i = instances.begin(); i!=instances.end(); ++i) {
71 (*i)->quit();
72 }
73 instancesMutex.unlock();
74}
75
76//------------------------------------------------------------------------------
77
78inline bool ServerThread::destroyHotkeys()
79{
80 if (hotkeys!=0) {
81 listenThread.getGlobals().getHotkeyHandler().unregisterHotkeys(hotkeys);
82 delete hotkeys; hotkeys = 0;
83 return true;
84 } else {
85 return false;
86 }
87}
88
89//------------------------------------------------------------------------------
90
91ServerThread::ServerThread(ListenThread& listenThread,
92 RequestQueue& requestQueue, LocalAcceptor& acceptor) :
93 Thread(true),
94 listenThread(listenThread),
95 requestQueue(requestQueue),
96 bufferedStream(acceptor.getSocket(&waiter)),
97 stream(*bufferedStream),
98 nextGetMultiRequestID(1),
99 nextSetMultiRequestID(1),
100 hotkeys(0)
101{
102 instancesMutex.lock();
103 instances.insert(this);
104 instancesMutex.unlock();
105}
106
107//------------------------------------------------------------------------------
108
109ServerThread::~ServerThread()
110{
111 delete bufferedStream;
112
113 for(getMultiRequests_t::iterator i = getMultiRequests.begin();
114 i!=getMultiRequests.end(); ++i)
115 {
116 delete i->second;
117 }
118
119 for(setMultiRequests_t::iterator i = setMultiRequests.begin();
120 i!=setMultiRequests.end(); ++i)
121 {
122 delete i->second;
123 }
124
125 instancesMutex.lock();
126 instances.erase(this);
127 instancesMutex.unlock();
128}
129
130//------------------------------------------------------------------------------
131
132void ServerThread::quit()
133{
134 stream.interrupt();
135}
136
137//------------------------------------------------------------------------------
138
139void ServerThread::run()
140{
141 Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run\n", this);
142 while(stream) {
143 uint8_t command = stream.readU8();
144 if (!stream) continue;
145
146 // Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run: command=0x%02x\n",
147 // this, command);
148
149 if (command==Protocol::COMMAND_GET_SINGLE) {
150 if (!handleGetSingle()) break;
151 } else if (command==Protocol::COMMAND_SET_SINGLE) {
152 if (!handleSetSingle()) break;
153 } else if (command==Protocol::COMMAND_GET_MULTI) {
154 if (!handleGetMulti()) break;
155 } else if (command==Protocol::COMMAND_SET_MULTI) {
156 if (!handleSetMulti()) break;
157 } else if (command==Protocol::COMMAND_REGISTER_GET_MULTI) {
158 if (!handleRegisterGetMulti()) break;
159 } else if (command==Protocol::COMMAND_UNREGISTER_GET_MULTI) {
160 if (!handleUnregisterGetMulti()) break;
161 } else if (command==Protocol::COMMAND_EXECUTE_GET_MULTI) {
162 if (!handleExecuteGetMulti()) break;
163 } else if (command==Protocol::COMMAND_REGISTER_SET_MULTI) {
164 if (!handleRegisterSetMulti()) break;
165 } else if (command==Protocol::COMMAND_UNREGISTER_SET_MULTI) {
166 if (!handleUnregisterSetMulti()) break;
167 } else if (command==Protocol::COMMAND_EXECUTE_SET_MULTI) {
168 if (!handleExecuteSetMulti()) break;
169 } else if (command==Protocol::COMMAND_GET_VERSIONS) {
170 if (!handleGetVersions()) break;
171 } else if (command==Protocol::COMMAND_RELOAD_PLUGINS) {
172 if (!handleReloadPlugins()) break;
173 } else if (command==Protocol::COMMAND_SHOW_MESSAGE) {
174 if (!handleShowMessage()) break;
175 } else if (command==Protocol::COMMAND_REGISTER_HOTKEYS) {
176 if (!handleRegisterHotkeys()) break;
177 } else if (command==Protocol::COMMAND_QUERY_HOTKEYS) {
178 if (!handleQueryHotkeys()) break;
179 } else if (command==Protocol::COMMAND_UNREGISTER_HOTKEYS) {
180 if (!handleUnregisterHotkeys()) break;
181 } else {
182 stream.writeU8(Protocol::RESULT_INVALID_COMMAND);
183 }
184 stream.flush();
185 }
186
187 destroyHotkeys();
188
189 Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run: quitting\n", this);
190}
191
192//------------------------------------------------------------------------------
193
194bool ServerThread::handleGetSingle()
195{
196 uint8_t result = Protocol::RESULT_OK;
197 GetDataRefTask* task = GetDataRefTask::create(result, stream);
198
199 if (!stream) {
200 return false;
201 } else if (task==0) {
202 stream.writeU8(result);
203 return true;
204 }
205
206 TaskRequest request(task);
207 if (!requestQueue.execute(&request)) return false;
208
209 if (task->isValid()) {
210 stream.writeU8(Protocol::RESULT_OK);
211 task->writeValue(stream);
212 } else {
213 stream.writeU8(Protocol::RESULT_UNKNOWN_DATAREF);
214 }
215
216 return true;
217}
218
219//------------------------------------------------------------------------------
220
221bool ServerThread::handleSetSingle()
222{
223 uint8_t result = Protocol::RESULT_OK;
224 SetDataRefTask* task = SetDataRefTask::create(result, stream);
225
226 if (!stream) {
227 return false;
228 } else if (task==0) {
229 stream.writeU8(result);
230 return true;
231 }
232
233 task->readValue(stream);
234 if (!stream) {
235 delete task;
236 return false;
237 }
238
239 TaskRequest request(task);
240 if (!requestQueue.execute(&request)) return false;
241
242 stream.writeU8(task->isValid() ? Protocol::RESULT_OK :
243 Protocol::RESULT_UNKNOWN_DATAREF);
244 return true;
245}
246
247//------------------------------------------------------------------------------
248
249bool ServerThread::handleGetMulti()
250{
251 uint8_t result = Protocol::RESULT_OK;
252 GetMultiDataRefRequest* request =
253 new GetMultiDataRefRequest(result, stream);
254 if (result!=Protocol::RESULT_OK || !stream) {
255 delete request;
256 stream.writeU8(result);
257 return stream;
258 }
259
260 bool isOK = requestQueue.execute(request);
261
262 if (isOK) {
263 request->writeResult(stream);
264 }
265
266 delete request;
267
268 return isOK;
269}
270
271//------------------------------------------------------------------------------
272
273bool ServerThread::handleSetMulti()
274{
275 uint8_t result = Protocol::RESULT_OK;
276 SetMultiDataRefRequest* request =
277 new SetMultiDataRefRequest(result, stream, true);
278 if (result!=Protocol::RESULT_OK || !stream) {
279 delete request;
280 stream.writeU8(result);
281 return stream;
282 }
283
284 bool isOK = requestQueue.execute(request);
285
286 if (isOK) {
287 request->writeResult(stream);
288 }
289
290 delete request;
291
292 return isOK;
293}
294
295//------------------------------------------------------------------------------
296
297bool ServerThread::handleRegisterGetMulti()
298{
299 uint8_t result = Protocol::RESULT_OK;
300 GetMultiDataRefRequest* request =
301 new GetMultiDataRefRequest(result, stream);
302 if (result!=Protocol::RESULT_OK || !stream) {
303 delete request;
304 stream.writeU8(result);
305 return stream;
306 }
307
308 size_t id = nextGetMultiRequestID++;
309 getMultiRequests[id] = request;
310
311 stream.writeU8(Protocol::RESULT_OK);
312 stream.writeU32(id);
313
314 return true;
315}
316
317//------------------------------------------------------------------------------
318
319bool ServerThread::handleUnregisterGetMulti()
320{
321 uint32_t id = stream.readU32();
322 if (!stream) return false;
323
324 getMultiRequests_t::iterator i = getMultiRequests.find(id);
325 if (i==getMultiRequests.end()) {
326 stream.writeU8(Protocol::RESULT_INVALID_ID);
327 } else {
328 GetMultiDataRefRequest* request = i->second;
329 getMultiRequests.erase(i);
330 delete request;
331 stream.writeU8(Protocol::RESULT_OK);
332 }
333
334 return true;
335}
336
337//------------------------------------------------------------------------------
338
339bool ServerThread::handleExecuteGetMulti()
340{
341 uint32_t id = stream.readU32();
342 if (!stream) return false;
343
344 getMultiRequests_t::iterator i = getMultiRequests.find(id);
345 if (i==getMultiRequests.end()) {
346 stream.writeU8(Protocol::RESULT_INVALID_ID);
347 } else {
348 GetMultiDataRefRequest* request = i->second;
349 if (!requestQueue.execute(request)) return false;
350 request->writeResult(stream);
351 }
352
353 return true;
354}
355
356//------------------------------------------------------------------------------
357
358bool ServerThread::handleRegisterSetMulti()
359{
360 uint8_t result = Protocol::RESULT_OK;
361 SetMultiDataRefRequest* request =
362 new SetMultiDataRefRequest(result, stream, false);
363 if (result!=Protocol::RESULT_OK || !stream) {
364 delete request;
365 stream.writeU8(result);
366 return stream;
367 }
368
369 size_t id = nextSetMultiRequestID++;
370 setMultiRequests[id] = request;
371
372 stream.writeU8(Protocol::RESULT_OK);
373 stream.writeU32(id);
374
375 return true;
376}
377
378//------------------------------------------------------------------------------
379
380bool ServerThread::handleUnregisterSetMulti()
381{
382 uint32_t id = stream.readU32();
383 if (!stream) return false;
384
385 setMultiRequests_t::iterator i = setMultiRequests.find(id);
386 if (i==setMultiRequests.end()) {
387 stream.writeU8(Protocol::RESULT_INVALID_ID);
388 } else {
389 SetMultiDataRefRequest* request = i->second;
390 setMultiRequests.erase(i);
391 delete request;
392 stream.writeU8(Protocol::RESULT_OK);
393 }
394
395 return true;
396}
397
398//------------------------------------------------------------------------------
399
400bool ServerThread::handleExecuteSetMulti()
401{
402 uint32_t id = stream.readU32();
403 if (!stream) return false;
404
405 setMultiRequests_t::iterator i = setMultiRequests.find(id);
406 if (i==setMultiRequests.end()) {
407 stream.writeU8(Protocol::RESULT_INVALID_ID);
408 } else {
409 SetMultiDataRefRequest* request = i->second;
410 request->readValues(stream);
411 if (!stream || !requestQueue.execute(request)) return false;
412 request->writeResult(stream);
413 }
414
415 return true;
416}
417
418//------------------------------------------------------------------------------
419
420bool ServerThread::handleGetVersions()
421{
422 int xplaneVersion = 0;
423 int xplmVersion = 0;
424
425 listenThread.getGlobals().getVersions(xplaneVersion, xplmVersion);
426
427 stream.writeU8(Protocol::RESULT_OK);
428 stream.writeS32(xplaneVersion);
429 stream.writeS32(xplmVersion);
430 stream.writeS32(Protocol::version);
431
432 return true;
433}
434
435//------------------------------------------------------------------------------
436
437bool ServerThread::handleReloadPlugins()
438{
439 ReloadPluginsRequest request;
440 if (!requestQueue.execute(&request)) return false;
441
442 stream.writeU8(Protocol::RESULT_OK);
443
444 return true;
445}
446
447//------------------------------------------------------------------------------
448
449bool ServerThread::handleShowMessage()
450{
451 string message = stream.readString();
452 float duration = stream.readFloat();
453 if (!stream) return false;
454
455 if (duration>Protocol::MAX_MESSAGE_DURATION) {
456 stream.writeU8(Protocol::RESULT_INVALID_DURATION);
457 } else {
458 MessageRequest request(listenThread.getGlobals().getMessageWindow(),
459 message, duration);
460 if (!requestQueue.execute(&request)) return false;
461
462 stream.writeU8(Protocol::RESULT_OK);
463 }
464
465 return true;
466}
467
468//------------------------------------------------------------------------------
469
470bool ServerThread::handleRegisterHotkeys()
471{
472 size_t numHotkeys = stream.readU32();
473 if (!stream) return false;
474
475 if (numHotkeys>Protocol::MAX_HOTKEY_COUNT) {
476 stream.writeU8(Protocol::RESULT_INVALID_LENGTH);
477 } else {
478 HotkeyHandler::Hotkeys* newHotkeys =
479 new HotkeyHandler::Hotkeys(numHotkeys, stream);
480 if (newHotkeys->isValid()) {
481 destroyHotkeys();
482 hotkeys = newHotkeys;
483 listenThread.getGlobals().getHotkeyHandler().registerHotkeys(hotkeys);
484 stream.writeU8(Protocol::RESULT_OK);
485 } else {
486 delete newHotkeys;
487 return false;
488 }
489 }
490
491 return true;
492}
493
494//------------------------------------------------------------------------------
495
496bool ServerThread::handleQueryHotkeys()
497{
498 stream.writeU8(Protocol::RESULT_OK);
499 if (hotkeys==0) {
500 stream.writeU32(0);
501 } else {
502 hotkeys->writePressed(stream);
503 }
504 return true;
505}
506
507//------------------------------------------------------------------------------
508
509bool ServerThread::handleUnregisterHotkeys()
510{
511 destroyHotkeys();
512 stream.writeU8(Protocol::RESULT_OK);
513 return true;
514}
515
516//------------------------------------------------------------------------------
517
518// Local Variables:
519// mode: C++
520// c-basic-offset: 4
521// indent-tabs-mode: nil
522// End:
Note: See TracBrowser for help on using the repository browser.