Rabbit Remote Control 0.0.30
Loading...
Searching...
No Matches
Connection.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include "Connection.h"
4#include "rfb/SSecurityVncAuth.h"
5#include "rfb/SMsgWriter.h"
6#include "rfb/screenTypes.h"
7#include "rfb/fenceTypes.h"
8#include "RabbitCommonTools.h"
9#include <fstream>
10#include "InputDevice.h"
11#include <QScreen>
12#include <QApplication>
13#include "Desktop.h"
14
15Q_DECLARE_LOGGING_CATEGORY(TigerVNC)
16
17static void setfile()
18{
19 const char* file = "/home/build-RabbitRemoteControl-Desktop_Qt_5_12_11_GCC_64bit-Debug/password";
20 char* pPass = new char[9];
21 strcpy(pPass, "123456");
22 rfb::PlainPasswd password(pPass);
23 rfb::ObfuscatedPasswd oPassword(password);
24 std::ofstream out;
25 out.open(file);
26 if(out.is_open())
27 {
28 out.write(oPassword.takeBuf(), oPassword.length);
29 out.close();
30 }
31 rfb::SSecurityVncAuth::vncAuthPasswdFile.setParam(file);
32}
33bool g_setfile = false;
34
35CConnection::CConnection(QSharedPointer<CChannel> channel,
37 : QObject(), rfb::SConnection(),
38 m_Channel(channel),
39 m_pPara(pPara),
40 m_PixelFormat(32, 24, false, true, 255, 255, 255, 16, 8, 0),
41 inProcessMessages(false),
42 pendingSyncFence(false),
43 syncFence(false),
44 fenceFlags(0),
45 fenceDataLen(0),
46 fenceData(nullptr),
47 m_EncodeManager(this),
48 continuousUpdates(false)
49{
50 bool check = false;
51
52 check = connect(m_Channel.data(), SIGNAL(sigConnected()),
53 this, SLOT(slotConnected()));
54 Q_ASSERT(check);
55 check = connect(m_Channel.data(), SIGNAL(readyRead()),
56 this, SLOT(slotReadyRead()));
57 Q_ASSERT(check);
58 check = connect(m_Channel.data(), SIGNAL(sigDisconnected()),
59 this, SLOT(slotDisconnected()));
60 Q_ASSERT(check);
61 check = connect(m_Channel.data(), SIGNAL(sigError(int, const QString&)),
62 this, SLOT(slotError(int, const QString&)));
63 Q_ASSERT(check);
64
65 m_InputDevice = CInputDevice::GenerateObject();
66}
67
68CConnection::~CConnection()
69{
70 qDebug(TigerVNC) << "CConnection::~CConnection";
71}
72
73void CConnection::slotConnected()
74{
75 try{
76 m_InStream = QSharedPointer<rdr::InStream>(new CInStreamChannel(m_Channel.data()));
77 m_OutStream = QSharedPointer<rdr::OutStream>(new COutStreamChannel(m_Channel.data()));
78 setStreams(m_InStream.data(), m_OutStream.data());
79
80 char* pass = new char[128];
81 strcpy(pass, m_pPara->getPassword().toStdString().c_str());
82 rfb::PlainPasswd password(pass);
83 rfb::ObfuscatedPasswd oPassword(password);
84 rfb::SSecurityVncAuth::vncAuthPasswd.setParam(oPassword.buf, oPassword.length);
85
86 client.setDimensions(CDesktop::Instance()->Width(), CDesktop::Instance()->Height());
87
88 initialiseProtocol();
89 } catch(rdr::Exception& e) {
90 std::string szErr ("initialistProtocol() fail:");
91 szErr += e.str();
92 qCritical(TigerVNC) << szErr.c_str();
93 emit sigError(-1, szErr.c_str());
94 } catch(std::exception& e) {
95 std::string szErr ("initialistProtocol() fail:");
96 szErr += e.what();
97 qCritical(TigerVNC) << szErr.c_str();
98 emit sigError(-1, szErr.c_str());
99 } catch(...) {
100 std::string szErr ("initialistProtocol() fail.");
101 qCritical(TigerVNC) << szErr.c_str();
102 emit sigError(-1, szErr.c_str());
103 }
104}
105
106void CConnection::slotReadyRead()
107{
108 qDebug(TigerVNC) << "CConnection::slotReadyRead()";
109 if (state() == RFBSTATE_CLOSING) return;
110 try {
111 inProcessMessages = true;
112
113 // Get the underlying transport to build large packets if we send
114 // multiple small responses.
115 getOutStream()->cork(true);
116
117 while (true) {
118 if (pendingSyncFence)
119 syncFence = true;
120
121 if (!processMsg())
122 break;
123
124 if (syncFence) {
125 writer()->writeFence(fenceFlags, fenceDataLen, fenceData);
126 syncFence = false;
127 pendingSyncFence = false;
128 }
129 }
130
131 // Flush out everything in case we go idle after this.
132 getOutStream()->cork(false);
133
134 inProcessMessages = false;
135
136 // If there were anything requiring an update, try to send it here.
137 // We wait until now with this to aggregate responses and to give
138 // higher priority to user actions such as keyboard and pointer events.
139 if(writer())
140 {
141 QImage img = CDesktop::Instance()->GetDesktop();
142 slotDesktopUpdate(img, img.rect());
143 }
144 } catch (rdr::Exception e) {
145 qCritical(TigerVNC) << "Exception:" << e.str();
146 emit sigError(-1, QString("processMsg exception:") + e.str());
147 } catch (std::exception e) {
148 qCritical(TigerVNC) << "std Exception:" << e.what();
149 emit sigError(-1, QString("std Exception:") + e.what());
150 } catch (...) {
151 qCritical(TigerVNC) << "exception";
152 emit sigError(-1, QString("Exception:"));
153 }
154}
155
156void CConnection::slotDisconnected()
157{
158 qDebug(TigerVNC) << "The connect disconnect";
159 emit sigDisconnected();
160}
161
162void CConnection::slotError(int nErr, const QString& szErr)
163{
164 emit sigError(nErr, szErr);
165}
166
167void CConnection::queryConnection(const char *userName)
168{
169 qDebug(TigerVNC) << "queryConnection:" << userName;
170 //TODO: check user is accept?
171 SConnection::queryConnection(userName);
172}
173
174void CConnection::authSuccess()
175{
176 qDebug(TigerVNC) << "CConnection::authSuccess(): state:" << state();
177 // Set the connection parameters appropriately
178 QString name = RabbitCommon::CTools::GetHostName()
179 + "@" + RabbitCommon::CTools::GetCurrentUser();
180 client.setName(name.toStdString().c_str());
181
182 //TODO: add client.setLEDState
183 // client.setLEDState
184
185 int w = CDesktop::Instance()->Width();
186 int h = CDesktop::Instance()->Height();
187 client.setDimensions(w, h);
188 client.setPF(m_PixelFormat);
189 char buffer[256];
190 client.pf().print(buffer, 256);
191 qInfo(TigerVNC, "Set server pixel format:%s; width:%d, height:%d",
192 buffer, w, h);
193
194 // Mark the entire display as "dirty"
195 m_Updates.add_changed(rfb::Rect(0, 0, w, w));
196}
197
198void CConnection::clientInit(bool shared)
199{
200 qDebug(TigerVNC) << "clientInit shared:" << shared;
201 SConnection::clientInit(shared);
202
203 bool check = connect(CDesktop::Instance(), SIGNAL(sigUpdate(QImage, QRect)),
204 this, SLOT(slotDesktopUpdate(QImage, QRect)));
205 Q_ASSERT(check);
206}
207
208void CConnection::setDesktopSize(int fb_width, int fb_height, const rfb::ScreenSet &layout)
209{
210 qDebug(TigerVNC, "setDesktopSize: %d:%d", fb_width, fb_height);
211
212 //TODO: Add set server desktop size
213
214 if(writer())
215 writer()->writeDesktopSize(rfb::reasonClient, rfb::resultSuccess);
216}
217
218void CConnection::setPixelFormat(const rfb::PixelFormat &pf)
219{
220 SConnection::setPixelFormat(pf);
221 char buffer[256];
222 pf.print(buffer, 256);
223 qDebug(TigerVNC) << "Set pixel format:" << buffer;
224
225 //TODO: add setCursor();
226
227}
228
229void CConnection::framebufferUpdateRequest(const rfb::Rect &r, bool incremental)
230{
231 /*
232 qDebug(TigerVNC, "framebufferUpdateRequest:incremental: %d; %d,%d,%d,%d",
233 incremental, r.tl.x, r.tl.y,
234 r.br.x, r.br.y);//*/
235 if (!accessCheck(AccessView)) return;
236
237 SConnection::framebufferUpdateRequest(r, incremental);
238
239 rfb::Rect safeRect;
240 // Check that the client isn't sending crappy requests
241 if (!r.enclosed_by(rfb::Rect(0, 0, client.width(), client.height()))) {
242 qCritical(TigerVNC, "FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
243 r.width(), r.height(), r.tl.x, r.tl.y,
244 client.width(), client.height());
245 safeRect = r.intersect(rfb::Rect(0, 0, client.width(), client.height()));
246 } else {
247 safeRect = r;
248 }
249
250 // Just update the requested region.
251 // Framebuffer update will be sent a bit later, see processMessages().
252 rfb::Region reqRgn(safeRect);
253 if (!incremental || !continuousUpdates)
254 requested.assign_union(reqRgn);
255
256 if (!incremental) {
257 // Non-incremental update - treat as if area requested has changed
258 m_Updates.add_changed(reqRgn);
259
260 // And send the screen layout to the client (which, unlike the
261 // framebuffer dimensions, the client doesn't get during init)
262 if (client.supportsEncoding(rfb::pseudoEncodingExtendedDesktopSize))
263 writer()->writeDesktopSize(rfb::reasonServer);
264
265 // We do not send a DesktopSize since it only contains the
266 // framebuffer size (which the client already should know) and
267 // because some clients don't handle extra DesktopSize events
268 // very well.
269 }
270}
271
272void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
273{
274 qDebug(TigerVNC, "fence: flags:%d,len:%d", flags, len);
275 rdr::U8 type;
276
277 if (flags & rfb::fenceFlagRequest) {
278 if (flags & rfb::fenceFlagSyncNext) {
279 pendingSyncFence = true;
280
281 fenceFlags = flags & (rfb::fenceFlagBlockBefore | rfb::fenceFlagBlockAfter | rfb::fenceFlagSyncNext);
282 fenceDataLen = len;
283 delete [] fenceData;
284 fenceData = NULL;
285 if (len > 0) {
286 fenceData = new char[len];
287 memcpy(fenceData, data, len);
288 }
289
290 return;
291 }
292
293 // We handle everything synchronously so we trivially honor these modes
294 flags = flags & (rfb::fenceFlagBlockBefore | rfb::fenceFlagBlockAfter);
295 if(writer())
296 writer()->writeFence(flags, len, data);
297 return;
298 }
299
300 if (len < 1)
301 qCritical(TigerVNC) << "Fence response of unexpected size received";
302
303 type = data[0];
304
305 switch (type) {
306 case 0:
307 // Initial dummy fence;
308 break;
309 case 1:
310 //congestion.gotPong();
311 break;
312 default:
313 qCritical(TigerVNC) << "Fence response of unexpected type received";
314 }
315}
316
317void CConnection::enableContinuousUpdates(bool enable, int x, int y, int w, int h)
318{
319 qDebug(TigerVNC, "enableContinuousUpdates: %d, %d,%d,%d,%d",
320 enable, x,y,w,h);
321 //SConnection::enableContinuousUpdates(enable, x, y, w, h);
322
323 rfb::Rect rect;
324
325 if (!client.supportsFence() || !client.supportsContinuousUpdates())
326 throw rdr::Exception("Client tried to enable continuous updates when not allowed");
327
328 continuousUpdates = enable;
329
330 rect.setXYWH(x, y, w, h);
331 cuRegion.reset(rect);
332
333 if (enable) {
334 requested.clear();
335 } else {
336 writer()->writeEndOfContinuousUpdates();
337 }
338}
339
340void CConnection::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
341{
342 qDebug(TigerVNC, "keysym:%d;keycode:%d;down:%d", keysym, keycode, down);
343 if(m_InputDevice)
344 m_InputDevice->KeyEvent(keysym, keycode, down);
345}
346
347void CConnection::pointerEvent(const rfb::Point &pos, int buttonMask)
348{
349 //qDebug(TigerVNC, "pos:%d,%d;button:%d", pos.x, pos.y, buttonMask);
350 CInputDevice::MouseButtons button;
351 if(buttonMask & 0x1)
352 button |= CInputDevice::LeftButton;
353 if(buttonMask & 0x2)
354 button |= CInputDevice::MouseButton::MiddleButton;
355 if(buttonMask & 0x4)
356 button |= CInputDevice::MouseButton::RightButton;
357 if(buttonMask & 0x8)
358 button |= CInputDevice::MouseButton::UWheelButton;
359 if(buttonMask & 0x10)
360 button |= CInputDevice::MouseButton::DWheelButton;
361 if(buttonMask & 0x20)
362 button |= CInputDevice::MouseButton::LWheelButton;
363 if(buttonMask & 0x40)
364 button |= CInputDevice::MouseButton::RWheelButton;
365
366 if(m_InputDevice)
367 m_InputDevice->MouseEvent(button, QPoint(pos.x, pos.y));
368}
369
370void CConnection::clientCutText(const char *str)
371{
372 qDebug(TigerVNC) << "cut text:" << str;
373}
374
375QSharedPointer<rfb::PixelBuffer> CConnection::GetBufferFromQImage(QImage &img)
376{
377 if(img.isNull())
378 return nullptr;
379
380 QSharedPointer<rfb::PixelBuffer> pb(
381 new rfb::FullFramePixelBuffer(m_PixelFormat,
382 img.width(),
383 img.height(),
384 img.bits(),
385 img.bytesPerLine()
386 / (m_PixelFormat.bpp / 8)));
387 return pb;
388}
389
390void CConnection::writeNoDataUpdate()
391{
392// if (!writer()->needNoDataUpdate())
393// return;
394
395 writer()->writeNoDataUpdate();
396
397 // Make sure no data update is sent until next request
398 //requested.clear();
399}
400
401void CConnection::writeDataUpdate(QImage img, QRect rect)
402{
403 rfb::Region req;
404 rfb::UpdateInfo ui;
405 const rfb::RenderedCursor *cursor = nullptr;
406
407 if(!writer()) return;
408
409 // See what the client has requested (if anything)
410 if (continuousUpdates)
411 req = cuRegion.union_(requested);
412 else
413 req = requested;
414
415 if (req.is_empty())
416 return;
417
418 if(img.isNull())
419 return;
420
421 // Get the lists of updates. Prior to exporting the data to the `ui' object,
422 // getUpdateInfo() will normalize the `updates' object such way that its
423 // `changed' and `copied' regions would not intersect.
424 m_Updates.getUpdateInfo(&ui, req);
425
426 QSharedPointer<rfb::PixelBuffer> buffer = GetBufferFromQImage(img);
427 m_EncodeManager.writeUpdate(ui, buffer.data(), cursor);
428
429}
430
431void CConnection::slotDesktopUpdate(QImage img, QRect rect)
432{
433 qDebug(TigerVNC) << "Update screen";
434 if(img.isNull() || !writer())
435 {
436 qCritical(TigerVNC) << "Image is null";
437 return;
438 }
439
440 writeDataUpdate(img, rect);
441}