~nobuto/ubuntu/natty/synergy/merge-from-experimental

« back to all changes in this revision

Viewing changes to lib/server/CClientProxy1_0.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Lutz
  • Date: 2003-10-31 19:36:30 UTC
  • Revision ID: james.westby@ubuntu.com-20031031193630-knbv79x5az7qh49y
Tags: upstream-1.0.14
ImportĀ upstreamĀ versionĀ 1.0.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * synergy -- mouse and keyboard sharing utility
 
3
 * Copyright (C) 2002 Chris Schoeneman
 
4
 * 
 
5
 * This package is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * found in the file COPYING that should have accompanied this file.
 
8
 * 
 
9
 * This package is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 */
 
14
 
 
15
#include "CClientProxy1_0.h"
 
16
#include "CServer.h"
 
17
#include "CClipboard.h"
 
18
#include "CProtocolUtil.h"
 
19
#include "XSynergy.h"
 
20
#include "IInputStream.h"
 
21
#include "IOutputStream.h"
 
22
#include "CLock.h"
 
23
#include "CThread.h"
 
24
#include "CLog.h"
 
25
#include "CStopwatch.h"
 
26
#include <cstring>
 
27
 
 
28
//
 
29
// CClientProxy1_0
 
30
//
 
31
 
 
32
CClientProxy1_0::CClientProxy1_0(IServer* server, const CString& name,
 
33
                                IInputStream* input, IOutputStream* output) :
 
34
        CClientProxy(server, name, input, output),
 
35
        m_heartRate(kHeartRate),
 
36
        m_heartDeath(kHeartRate * kHeartBeatsUntilDeath)
 
37
{
 
38
        for (UInt32 i = 0; i < kClipboardEnd; ++i) {
 
39
                m_clipboardDirty[i] = true;
 
40
        }
 
41
}
 
42
 
 
43
CClientProxy1_0::~CClientProxy1_0()
 
44
{
 
45
        // do nothing
 
46
}
 
47
 
 
48
void
 
49
CClientProxy1_0::open()
 
50
{
 
51
        // send request
 
52
        LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
 
53
        CProtocolUtil::writef(getOutputStream(), kMsgQInfo);
 
54
        getOutputStream()->flush();
 
55
 
 
56
        // wait for and verify reply
 
57
        UInt8 code[4];
 
58
        for (;;) {
 
59
                UInt32 n = getInputStream()->read(code, 4, -1.0);
 
60
                if (n == 4) {
 
61
                        if (memcmp(code, kMsgCNoop, 4) == 0) {
 
62
                                // discard heartbeats
 
63
                                continue;
 
64
                        }
 
65
                        if (memcmp(code, kMsgDInfo, 4) == 0) {
 
66
                                break;
 
67
                        }
 
68
                }
 
69
                throw XBadClient();
 
70
        }
 
71
 
 
72
        // handle reply
 
73
        recvInfo(false);
 
74
}
 
75
 
 
76
void
 
77
CClientProxy1_0::mainLoop()
 
78
{
 
79
        // handle messages until the client hangs up or stops sending heartbeats
 
80
        CStopwatch heartTimer;
 
81
        for (;;) {
 
82
                CThread::testCancel();
 
83
 
 
84
                // wait for a message
 
85
                UInt8 code[4];
 
86
                UInt32 n = getInputStream()->read(code, 4, m_heartRate);
 
87
                CThread::testCancel();
 
88
 
 
89
                // check if client hungup
 
90
                if (n == 0) {
 
91
                        LOG((CLOG_NOTE "client \"%s\" disconnected", getName().c_str()));
 
92
                        return;
 
93
                }
 
94
 
 
95
                // check if client has stopped sending heartbeats
 
96
                if (n == (UInt32)-1) {
 
97
                        if (m_heartDeath >= 0.0 && heartTimer.getTime() > m_heartDeath) {
 
98
                                LOG((CLOG_NOTE "client \"%s\" is dead", getName().c_str()));
 
99
                                return;
 
100
                        }
 
101
                        continue;
 
102
                }
 
103
 
 
104
                // got a message so reset heartbeat monitor
 
105
                heartTimer.reset();
 
106
 
 
107
                // verify we got an entire code
 
108
                if (n != 4) {
 
109
                        LOG((CLOG_ERR "incomplete message from \"%s\": %d bytes", getName().c_str(), n));
 
110
 
 
111
                        // client sent an incomplete message
 
112
                        throw XBadClient();
 
113
                }
 
114
 
 
115
                // parse message
 
116
                LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
 
117
                if (memcmp(code, kMsgDInfo, 4) == 0) {
 
118
                        recvInfo(true);
 
119
                }
 
120
                else if (memcmp(code, kMsgCNoop, 4) == 0) {
 
121
                        // discard no-ops
 
122
                        LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
 
123
                        continue;
 
124
                }
 
125
                else if (memcmp(code, kMsgCClipboard, 4) == 0) {
 
126
                        recvGrabClipboard();
 
127
                }
 
128
                else if (memcmp(code, kMsgDClipboard, 4) == 0) {
 
129
                        recvClipboard();
 
130
                }
 
131
                // note -- more message handlers go here
 
132
                else {
 
133
                        LOG((CLOG_ERR "invalid message from client \"%s\"", getName().c_str()));
 
134
 
 
135
                        // unknown message
 
136
                        throw XBadClient();
 
137
                }
 
138
        }
 
139
}
 
140
 
 
141
void
 
142
CClientProxy1_0::close()
 
143
{
 
144
        LOG((CLOG_DEBUG1 "send close to \"%s\"", getName().c_str()));
 
145
        CProtocolUtil::writef(getOutputStream(), kMsgCClose);
 
146
 
 
147
        // force the close to be sent before we return
 
148
        getOutputStream()->flush();
 
149
}
 
150
 
 
151
void
 
152
CClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs,
 
153
                                UInt32 seqNum, KeyModifierMask mask, bool)
 
154
{
 
155
        LOG((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), xAbs, yAbs, seqNum, mask));
 
156
        CProtocolUtil::writef(getOutputStream(), kMsgCEnter,
 
157
                                                                xAbs, yAbs, seqNum, mask);
 
158
}
 
159
 
 
160
bool
 
161
CClientProxy1_0::leave()
 
162
{
 
163
        LOG((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str()));
 
164
        CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
 
165
 
 
166
        // we can never prevent the user from leaving
 
167
        return true;
 
168
}
 
169
 
 
170
void
 
171
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
 
172
{
 
173
        // ignore if this clipboard is already clean
 
174
        CLock lock(getMutex());
 
175
        if (m_clipboardDirty[id]) {
 
176
                // this clipboard is now clean
 
177
                m_clipboardDirty[id] = false;
 
178
 
 
179
                LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
 
180
                CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, 0, &data);
 
181
        }
 
182
}
 
183
 
 
184
void
 
185
CClientProxy1_0::grabClipboard(ClipboardID id)
 
186
{
 
187
        LOG((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str()));
 
188
        CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, 0);
 
189
 
 
190
        // this clipboard is now dirty
 
191
        CLock lock(getMutex());
 
192
        m_clipboardDirty[id] = true;
 
193
}
 
194
 
 
195
void
 
196
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
 
197
{
 
198
        CLock lock(getMutex());
 
199
        m_clipboardDirty[id] = dirty;
 
200
}
 
201
 
 
202
void
 
203
CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton)
 
204
{
 
205
        LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
 
206
        CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown1_0, key, mask);
 
207
}
 
208
 
 
209
void
 
210
CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask,
 
211
                                SInt32 count, KeyButton)
 
212
{
 
213
        LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count));
 
214
        CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat1_0, key, mask, count);
 
215
}
 
216
 
 
217
void
 
218
CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton)
 
219
{
 
220
        LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
 
221
        CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp1_0, key, mask);
 
222
}
 
223
 
 
224
void
 
225
CClientProxy1_0::mouseDown(ButtonID button)
 
226
{
 
227
        LOG((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), button));
 
228
        CProtocolUtil::writef(getOutputStream(), kMsgDMouseDown, button);
 
229
}
 
230
 
 
231
void
 
232
CClientProxy1_0::mouseUp(ButtonID button)
 
233
{
 
234
        LOG((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button));
 
235
        CProtocolUtil::writef(getOutputStream(), kMsgDMouseUp, button);
 
236
}
 
237
 
 
238
void
 
239
CClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs)
 
240
{
 
241
        LOG((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, yAbs));
 
242
        CProtocolUtil::writef(getOutputStream(), kMsgDMouseMove, xAbs, yAbs);
 
243
}
 
244
 
 
245
void
 
246
CClientProxy1_0::mouseWheel(SInt32 delta)
 
247
{
 
248
        LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), delta));
 
249
        CProtocolUtil::writef(getOutputStream(), kMsgDMouseWheel, delta);
 
250
}
 
251
 
 
252
void
 
253
CClientProxy1_0::screensaver(bool on)
 
254
{
 
255
        LOG((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0));
 
256
        CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0);
 
257
}
 
258
 
 
259
void
 
260
CClientProxy1_0::resetOptions()
 
261
{
 
262
        LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str()));
 
263
        CProtocolUtil::writef(getOutputStream(), kMsgCResetOptions);
 
264
 
 
265
        // reset heart rate and death
 
266
        CLock lock(getMutex());
 
267
        m_heartRate  = kHeartRate;
 
268
        m_heartDeath = kHeartRate * kHeartBeatsUntilDeath;
 
269
}
 
270
 
 
271
void
 
272
CClientProxy1_0::setOptions(const COptionsList& options)
 
273
{
 
274
        LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), options.size()));
 
275
        CProtocolUtil::writef(getOutputStream(), kMsgDSetOptions, &options);
 
276
 
 
277
        // check options
 
278
        CLock lock(getMutex());
 
279
        for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
 
280
                if (options[i] == kOptionHeartbeat) {
 
281
                        m_heartRate = 1.0e-3 * static_cast<double>(options[i + 1]);
 
282
                        if (m_heartRate <= 0.0) {
 
283
                                m_heartRate = -1.0;
 
284
                        }
 
285
                        m_heartDeath = m_heartRate * kHeartBeatsUntilDeath;
 
286
                }
 
287
        }
 
288
}
 
289
 
 
290
SInt32
 
291
CClientProxy1_0::getJumpZoneSize() const
 
292
{
 
293
        CLock lock(getMutex());
 
294
        return m_info.m_zoneSize;
 
295
}
 
296
 
 
297
void
 
298
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
 
299
{
 
300
        CLock lock(getMutex());
 
301
        x = m_info.m_x;
 
302
        y = m_info.m_y;
 
303
        w = m_info.m_w;
 
304
        h = m_info.m_h;
 
305
}
 
306
 
 
307
void
 
308
CClientProxy1_0::getCursorPos(SInt32&, SInt32&) const
 
309
{
 
310
        assert(0 && "shouldn't be called");
 
311
}
 
312
 
 
313
void
 
314
CClientProxy1_0::getCursorCenter(SInt32& x, SInt32& y) const
 
315
{
 
316
        CLock lock(getMutex());
 
317
        x = m_info.m_mx;
 
318
        y = m_info.m_my;
 
319
}
 
320
 
 
321
void
 
322
CClientProxy1_0::recvInfo(bool notify)
 
323
{
 
324
        {
 
325
                CLock lock(getMutex());
 
326
 
 
327
                // parse the message
 
328
                SInt16 x, y, w, h, zoneSize, mx, my;
 
329
                CProtocolUtil::readf(getInputStream(), kMsgDInfo + 4,
 
330
                                                                &x, &y, &w, &h, &zoneSize, &mx, &my);
 
331
                LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getName().c_str(), x, y, w, h, zoneSize, mx, my));
 
332
 
 
333
                // validate
 
334
                if (w <= 0 || h <= 0 || zoneSize < 0) {
 
335
                        throw XBadClient();
 
336
                }
 
337
                if (mx < x || my < y || mx >= x + w || my >= y + h) {
 
338
                        throw XBadClient();
 
339
                }
 
340
 
 
341
                // save
 
342
                m_info.m_x        = x;
 
343
                m_info.m_y        = y;
 
344
                m_info.m_w        = w;
 
345
                m_info.m_h        = h;
 
346
                m_info.m_zoneSize = zoneSize;
 
347
                m_info.m_mx       = mx;
 
348
                m_info.m_my       = my;
 
349
        }
 
350
 
 
351
        // tell server of change
 
352
        if (notify) {
 
353
                getServer()->onInfoChanged(getName(), m_info);
 
354
        }
 
355
 
 
356
        // acknowledge receipt
 
357
        LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
 
358
        CProtocolUtil::writef(getOutputStream(), kMsgCInfoAck);
 
359
}
 
360
 
 
361
void
 
362
CClientProxy1_0::recvClipboard()
 
363
{
 
364
        // parse message
 
365
        ClipboardID id;
 
366
        UInt32 seqNum;
 
367
        CString data;
 
368
        CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &id, &seqNum, &data);
 
369
        LOG((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", getName().c_str(), id, seqNum, data.size()));
 
370
 
 
371
        // validate
 
372
        if (id >= kClipboardEnd) {
 
373
                throw XBadClient();
 
374
        }
 
375
 
 
376
        // send update.  this calls us back to reset our clipboard dirty flag
 
377
        // so don't hold a lock during the call.
 
378
        getServer()->onClipboardChanged(id, seqNum, data);
 
379
}
 
380
 
 
381
void
 
382
CClientProxy1_0::recvGrabClipboard()
 
383
{
 
384
        // parse message
 
385
        ClipboardID id;
 
386
        UInt32 seqNum;
 
387
        CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
 
388
        LOG((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getName().c_str(), id, seqNum));
 
389
 
 
390
        // validate
 
391
        if (id >= kClipboardEnd) {
 
392
                throw XBadClient();
 
393
        }
 
394
 
 
395
        // send update.  this calls us back to reset our clipboard dirty flag
 
396
        // so don't hold a lock during the call.
 
397
        getServer()->onGrabClipboard(getName(), id, seqNum);
 
398
}