1 /*
2  * synergy -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2002 Chris Schoeneman
5  *
6  * This package is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * found in the file LICENSE that should have accompanied this file.
9  *
10  * This package 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, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include "server/Config.h"
22 #include "synergy/clipboard_types.h"
23 #include "synergy/Clipboard.h"
24 #include "synergy/key_types.h"
25 #include "synergy/mouse_types.h"
26 #include "synergy/INode.h"
27 #include "synergy/DragInformation.h"
28 #include "synergy/ServerArgs.h"
29 #include "base/Event.h"
30 #include "base/Stopwatch.h"
31 #include "base/EventTypes.h"
32 #include "common/stdmap.h"
33 #include "common/stdset.h"
34 #include "common/stdvector.h"
35 
36 class BaseClientProxy;
37 class EventQueueTimer;
38 class PrimaryClient;
39 class InputFilter;
40 namespace synergy { class Screen; }
41 class IEventQueue;
42 class Thread;
43 class ClientListener;
44 
45 //! Synergy server
46 /*!
47 This class implements the top-level server algorithms for synergy.
48 */
49 class Server : public INode {
50 public:
51     //! Lock cursor to screen data
52     class LockCursorToScreenInfo {
53     public:
54         enum State { kOff, kOn, kToggle };
55 
56         static LockCursorToScreenInfo* alloc(State state = kToggle);
57 
58     public:
59         State            m_state;
60     };
61 
62     //! Switch to screen data
63     class SwitchToScreenInfo {
64     public:
65         static SwitchToScreenInfo* alloc(const String& screen);
66 
67     public:
68         // this is a C-string;  this type is a variable size structure
69         char            m_screen[1];
70     };
71 
72     //! Switch in direction data
73     class SwitchInDirectionInfo {
74     public:
75         static SwitchInDirectionInfo* alloc(EDirection direction);
76 
77     public:
78         EDirection        m_direction;
79     };
80 
81     //! Screen connected data
82     class ScreenConnectedInfo {
83     public:
ScreenConnectedInfo(String screen)84         ScreenConnectedInfo(String screen) : m_screen(screen) { }
85 
86     public:
87         String            m_screen; // was char[1]
88     };
89 
90     //! Keyboard broadcast data
91     class KeyboardBroadcastInfo {
92     public:
93         enum State { kOff, kOn, kToggle };
94 
95         static KeyboardBroadcastInfo* alloc(State state = kToggle);
96         static KeyboardBroadcastInfo* alloc(State state,
97                                             const String& screens);
98 
99     public:
100         State            m_state;
101         char            m_screens[1];
102     };
103 
104     /*!
105     Start the server with the configuration \p config and the primary
106     client (local screen) \p primaryClient.  The client retains
107     ownership of \p primaryClient.
108     */
109     Server(Config& config, PrimaryClient* primaryClient,
110         synergy::Screen* screen, IEventQueue* events, lib::synergy::ServerArgs const& args);
111     Server(Server const &) =delete;
112     Server(Server &&) =delete;
113     ~Server();
114 
115     Server& operator=(Server const &) =delete;
116     Server& operator=(Server &&) =delete;
117 
118 #ifdef TEST_ENV
Server()119     Server() : m_mock(true), m_config(NULL) { }
setActive(BaseClientProxy * active)120     void setActive(BaseClientProxy* active) {    m_active = active; }
121 #endif
122 
123     //! @name manipulators
124     //@{
125 
126     //! Set configuration
127     /*!
128     Change the server's configuration.  Returns true iff the new
129     configuration was accepted (it must include the server's name).
130     This will disconnect any clients no longer in the configuration.
131     */
132     bool                setConfig(const Config&);
133 
134     //! Add a client
135     /*!
136     Adds \p client to the server.  The client is adopted and will be
137     destroyed when the client disconnects or is disconnected.
138     */
139     void                adoptClient(BaseClientProxy* client);
140 
141     //! Disconnect clients
142     /*!
143     Disconnect clients.  This tells them to disconnect but does not wait
144     for them to actually do so.  The server sends the disconnected event
145     when they're all disconnected (or immediately if none are connected).
146     The caller can also just destroy this object to force the disconnection.
147     */
148     void                disconnect();
149 
150     //! Create a new thread and use it to send file to client
151     void                sendFileToClient(const char* filename);
152 
153     //! Received dragging information from client
154     void                dragInfoReceived(UInt32 fileNum, String content);
155 
156     //! Store ClientListener pointer
setListener(ClientListener * p)157     void                setListener(ClientListener* p) { m_clientListener = p; }
158 
159     //@}
160     //! @name accessors
161     //@{
162 
163     //! Get number of connected clients
164     /*!
165     Returns the number of connected clients, including the server itself.
166     */
167     UInt32                getNumClients() const;
168 
169     //! Get the list of connected clients
170     /*!
171     Set the \c list to the names of the currently connected clients.
172     */
173     void                getClients(std::vector<String>& list) const;
174 
175     //! Return true if recieved file size is valid
176     bool                isReceivedFileSizeValid();
177 
178     //! Return expected file data size
getExpectedFileSize()179     size_t&                getExpectedFileSize() { return m_expectedFileSize; }
180 
181     //! Return received file data
getReceivedFileData()182     String&                getReceivedFileData() { return m_receivedFileData; }
183 
184     //! Return fake drag file list
getFakeDragFileList()185     DragFileList        getFakeDragFileList() { return m_fakeDragFileList; }
186 
187     //@}
188 
189 private:
190     // get canonical name of client
191     String                getName(const BaseClientProxy*) const;
192 
193     // get the sides of the primary screen that have neighbors
194     UInt32                getActivePrimarySides() const;
195 
196     // returns true iff mouse should be locked to the current screen
197     // according to this object only, ignoring what the primary client
198     // says.
199     bool                isLockedToScreenServer() const;
200 
201     // returns true iff mouse should be locked to the current screen
202     // according to this object or the primary client.
203     bool                isLockedToScreen() const;
204 
205     // returns the jump zone of the client
206     SInt32                getJumpZoneSize(BaseClientProxy*) const;
207 
208     // change the active screen
209     void                switchScreen(BaseClientProxy*,
210                             SInt32 x, SInt32 y, bool forScreenSaver);
211 
212     // jump to screen
213     void                jumpToScreen(BaseClientProxy*);
214 
215     // convert pixel position to fraction, using x or y depending on the
216     // direction.
217     float                mapToFraction(BaseClientProxy*, EDirection,
218                             SInt32 x, SInt32 y) const;
219 
220     // convert fraction to pixel position, writing only x or y depending
221     // on the direction.
222     void                mapToPixel(BaseClientProxy*, EDirection, float f,
223                             SInt32& x, SInt32& y) const;
224 
225     // returns true if the client has a neighbor anywhere along the edge
226     // indicated by the direction.
227     bool                hasAnyNeighbor(BaseClientProxy*, EDirection) const;
228 
229     // lookup neighboring screen, mapping the coordinate independent of
230     // the direction to the neighbor's coordinate space.
231     BaseClientProxy*    getNeighbor(BaseClientProxy*, EDirection,
232                             SInt32& x, SInt32& y) const;
233 
234     // lookup neighboring screen.  given a position relative to the
235     // source screen, find the screen we should move onto and where.
236     // if the position is sufficiently far from the source then we
237     // cross multiple screens.  if there is no suitable screen then
238     // return NULL and x,y are not modified.
239     BaseClientProxy*    mapToNeighbor(BaseClientProxy*, EDirection,
240                             SInt32& x, SInt32& y) const;
241 
242     // adjusts x and y or neither to avoid ending up in a jump zone
243     // after entering the client in the given direction.
244     void                avoidJumpZone(BaseClientProxy*, EDirection,
245                             SInt32& x, SInt32& y) const;
246 
247     // test if a switch is permitted.  this includes testing user
248     // options like switch delay and tracking any state required to
249     // implement them.  returns true iff a switch is permitted.
250     bool                isSwitchOkay(BaseClientProxy* dst, EDirection,
251                             SInt32 x, SInt32 y, SInt32 xActive, SInt32 yActive);
252 
253     // update switch state due to a mouse move at \p x, \p y that
254     // doesn't switch screens.
255     void                noSwitch(SInt32 x, SInt32 y);
256 
257     // stop switch timers
258     void                stopSwitch();
259 
260     // start two tap switch timer
261     void                startSwitchTwoTap();
262 
263     // arm the two tap switch timer if \p x, \p y is outside the tap zone
264     void                armSwitchTwoTap(SInt32 x, SInt32 y);
265 
266     // stop the two tap switch timer
267     void                stopSwitchTwoTap();
268 
269     // returns true iff the two tap switch timer is started
270     bool                isSwitchTwoTapStarted() const;
271 
272     // returns true iff should switch because of two tap
273     bool                shouldSwitchTwoTap() const;
274 
275     // start delay switch timer
276     void                startSwitchWait(SInt32 x, SInt32 y);
277 
278     // stop delay switch timer
279     void                stopSwitchWait();
280 
281     // returns true iff the delay switch timer is started
282     bool                isSwitchWaitStarted() const;
283 
284     // returns the corner (EScreenSwitchCornerMasks) where x,y is on the
285     // given client.  corners have the given size.
286     UInt32                getCorner(BaseClientProxy*,
287                             SInt32 x, SInt32 y, SInt32 size) const;
288 
289     // stop relative mouse moves
290     void                stopRelativeMoves();
291 
292     // send screen options to \c client
293     void                sendOptions(BaseClientProxy* client) const;
294 
295     // process options from configuration
296     void                processOptions();
297 
298     // event handlers
299     void                handleShapeChanged(const Event&, void*);
300     void                handleClipboardGrabbed(const Event&, void*);
301     void                handleClipboardChanged(const Event&, void*);
302     void                handleKeyDownEvent(const Event&, void*);
303     void                handleKeyUpEvent(const Event&, void*);
304     void                handleKeyRepeatEvent(const Event&, void*);
305     void                handleButtonDownEvent(const Event&, void*);
306     void                handleButtonUpEvent(const Event&, void*);
307     void                handleMotionPrimaryEvent(const Event&, void*);
308     void                handleMotionSecondaryEvent(const Event&, void*);
309     void                handleWheelEvent(const Event&, void*);
310     void                handleScreensaverActivatedEvent(const Event&, void*);
311     void                handleScreensaverDeactivatedEvent(const Event&, void*);
312     void                handleSwitchWaitTimeout(const Event&, void*);
313     void                handleClientDisconnected(const Event&, void*);
314     void                handleClientCloseTimeout(const Event&, void*);
315     void                handleSwitchToScreenEvent(const Event&, void*);
316     void                handleSwitchInDirectionEvent(const Event&, void*);
317     void                handleKeyboardBroadcastEvent(const Event&,void*);
318     void                handleLockCursorToScreenEvent(const Event&, void*);
319     void                handleFakeInputBeginEvent(const Event&, void*);
320     void                handleFakeInputEndEvent(const Event&, void*);
321     void                handleFileChunkSendingEvent(const Event&, void*);
322     void                handleFileRecieveCompletedEvent(const Event&, void*);
323 
324     // event processing
325     void                onClipboardChanged(BaseClientProxy* sender,
326                             ClipboardID id, UInt32 seqNum);
327     void                onScreensaver(bool activated);
328     void                onKeyDown(KeyID, KeyModifierMask, KeyButton,
329                             const char* screens);
330     void                onKeyUp(KeyID, KeyModifierMask, KeyButton,
331                             const char* screens);
332     void                onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton);
333     void                onMouseDown(ButtonID);
334     void                onMouseUp(ButtonID);
335     bool                onMouseMovePrimary(SInt32 x, SInt32 y);
336     void                onMouseMoveSecondary(SInt32 dx, SInt32 dy);
337     void                onMouseWheel(SInt32 xDelta, SInt32 yDelta);
338     void                onFileChunkSending(const void* data);
339     void                onFileRecieveCompleted();
340 
341     // add client to list and attach event handlers for client
342     bool                addClient(BaseClientProxy*);
343 
344     // remove client from list and detach event handlers for client
345     bool                removeClient(BaseClientProxy*);
346 
347     // close a client
348     void                closeClient(BaseClientProxy*, const char* msg);
349 
350     // close clients not in \p config
351     void                closeClients(const Config& config);
352 
353     // close all clients whether they've completed the handshake or not,
354     // except the primary client
355     void                closeAllClients();
356 
357     // remove clients from internal state
358     void                removeActiveClient(BaseClientProxy*);
359     void                removeOldClient(BaseClientProxy*);
360 
361     // force the cursor off of \p client
362     void                forceLeaveClient(BaseClientProxy* client);
363 
364     // thread funciton for sending file
365     void                sendFileThread(void*);
366 
367     // thread function for writing file to drop directory
368     void                writeToDropDirThread(void*);
369 
370     // thread function for sending drag information
371     void                sendDragInfoThread(void*);
372 
373     // send drag info to new client screen
374     void                sendDragInfo(BaseClientProxy* newScreen);
375 
376 public:
377     bool                m_mock;
378 
379 private:
380     class ClipboardInfo {
381     public:
382         ClipboardInfo();
383 
384     public:
385         Clipboard        m_clipboard;
386         String            m_clipboardData;
387         String            m_clipboardOwner;
388         UInt32            m_clipboardSeqNum;
389     };
390 
391     // the primary screen client
392     PrimaryClient*        m_primaryClient;
393 
394     // all clients (including the primary client) indexed by name
395     typedef std::map<String, BaseClientProxy*> ClientList;
396     typedef std::set<BaseClientProxy*> ClientSet;
397     ClientList            m_clients;
398     ClientSet            m_clientSet;
399 
400     // all old connections that we're waiting to hangup
401     typedef std::map<BaseClientProxy*, EventQueueTimer*> OldClients;
402     OldClients            m_oldClients;
403 
404     // the client with focus
405     BaseClientProxy*    m_active;
406 
407     // the sequence number of enter messages
408     UInt32                m_seqNum;
409 
410     // current mouse position (in absolute screen coordinates) on
411     // whichever screen is active
412     SInt32                m_x, m_y;
413 
414     // last mouse deltas.  this is needed to smooth out double tap
415     // on win32 which reports bogus mouse motion at the edge of
416     // the screen when using low level hooks, synthesizing motion
417     // in the opposite direction the mouse actually moved.
418     SInt32                m_xDelta, m_yDelta;
419     SInt32                m_xDelta2, m_yDelta2;
420 
421     // current configuration
422     Config*                m_config;
423 
424     // input filter (from m_config);
425     InputFilter*        m_inputFilter;
426 
427     // clipboard cache
428     ClipboardInfo        m_clipboards[kClipboardEnd];
429 
430     // state saved when screen saver activates
431     BaseClientProxy*    m_activeSaver;
432     SInt32                m_xSaver, m_ySaver;
433 
434     // common state for screen switch tests.  all tests are always
435     // trying to reach the same screen in the same direction.
436     EDirection            m_switchDir;
437     BaseClientProxy*    m_switchScreen;
438 
439     // state for delayed screen switching
440     double                m_switchWaitDelay;
441     EventQueueTimer*    m_switchWaitTimer;
442     SInt32                m_switchWaitX, m_switchWaitY;
443 
444     // state for double-tap screen switching
445     double                m_switchTwoTapDelay;
446     Stopwatch            m_switchTwoTapTimer;
447     bool                m_switchTwoTapEngaged;
448     bool                m_switchTwoTapArmed;
449     SInt32                m_switchTwoTapZone;
450 
451     // modifiers needed before switching
452     bool                m_switchNeedsShift;
453     bool                m_switchNeedsControl;
454     bool                m_switchNeedsAlt;
455 
456     // relative mouse move option
457     bool                m_relativeMoves;
458 
459     // flag whether or not we have broadcasting enabled and the screens to
460     // which we should send broadcasted keys.
461     bool                m_keyboardBroadcasting;
462     String                m_keyboardBroadcastingScreens;
463 
464     // screen locking (former scroll lock)
465     bool                m_lockedToScreen;
466 
467     // server screen
468     synergy::Screen*    m_screen;
469 
470     IEventQueue*        m_events;
471 
472     // file transfer
473     size_t                m_expectedFileSize;
474     String                m_receivedFileData;
475     DragFileList        m_dragFileList;
476     DragFileList        m_fakeDragFileList;
477     Thread*                m_sendFileThread;
478     Thread*                m_writeToDropDirThread;
479     String                m_dragFileExt;
480     bool                m_ignoreFileTransfer;
481     bool                m_disableLockToScreen;
482     bool                m_enableClipboard;
483     size_t				m_maximumClipboardSize;
484 
485     Thread*                m_sendDragInfoThread;
486     bool                m_waitDragInfoThread;
487 
488     ClientListener*        m_clientListener;
489     lib::synergy::ServerArgs            m_args;
490 };
491