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#include <QLoggingCategory>
15Q_DECLARE_LOGGING_CATEGORY(RabbitVNC)
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(RabbitVNC) << "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(RabbitVNC) << 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(RabbitVNC) << szErr.c_str();
98 emit sigError(-1, szErr.c_str());
99 } catch(...) {
100 std::string szErr ("initialistProtocol() fail.");
101 qCritical(RabbitVNC) << szErr.c_str();
102 emit sigError(-1, szErr.c_str());
103 }
104}
105
106void CConnection::slotReadyRead()
107{
108 qDebug(RabbitVNC) << "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(RabbitVNC) << "Exception:" << e.str();
146 emit sigError(-1, QString("processMsg exception:") + e.str());
147 } catch (std::exception e) {
148 qCritical(RabbitVNC) << "std Exception:" << e.what();
149 emit sigError(-1, QString("std Exception:") + e.what());
150 } catch (...) {
151 qCritical(RabbitVNC) << "exception";
152 emit sigError(-1, QString("Exception:"));
153 }
154}
155
156void CConnection::slotDisconnected()
157{
158 qDebug(RabbitVNC) << "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(RabbitVNC) << "queryConnection:" << userName;
170 //TODO: check user is accept?
171 SConnection::queryConnection(userName);
172}
173
174void CConnection::authSuccess()
175{
176 qDebug(RabbitVNC) << "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(RabbitVNC) << "Set server pixel format:" << buffer << "width:" << w << "height:" << h;
192
193 // Mark the entire display as "dirty"
194 m_Updates.add_changed(rfb::Rect(0, 0, w, w));
195}
196
197void CConnection::clientInit(bool shared)
198{
199 qInfo(RabbitVNC) << "clientInit shared:" << shared;
200 SConnection::clientInit(shared);
201
202 bool check = connect(CDesktop::Instance(), SIGNAL(sigUpdate(QImage, QRect)),
203 this, SLOT(slotDesktopUpdate(QImage, QRect)));
204 Q_ASSERT(check);
205}
206
207void CConnection::setDesktopSize(int fb_width, int fb_height, const rfb::ScreenSet &layout)
208{
209 qInfo(RabbitVNC) << "setDesktopSize: " << fb_width << fb_height;
210
211 //TODO: Add set server desktop size
212
213 if(writer())
214 writer()->writeDesktopSize(rfb::reasonClient, rfb::resultSuccess);
215}
216
217void CConnection::setPixelFormat(const rfb::PixelFormat &pf)
218{
219 SConnection::setPixelFormat(pf);
220 char buffer[256];
221 pf.print(buffer, 256);
222 qDebug(RabbitVNC) << "Set pixel format:" << buffer;
223
224 //TODO: add setCursor();
225
226}
227
228void CConnection::framebufferUpdateRequest(const rfb::Rect &r, bool incremental)
229{
230 /*
231 qDebug(RabbitVNC, "framebufferUpdateRequest:incremental: %d; %d,%d,%d,%d",
232 incremental, r.tl.x, r.tl.y,
233 r.br.x, r.br.y);//*/
234 if (!accessCheck(AccessView)) return;
235
236 SConnection::framebufferUpdateRequest(r, incremental);
237
238 rfb::Rect safeRect;
239 // Check that the client isn't sending crappy requests
240 if (!r.enclosed_by(rfb::Rect(0, 0, client.width(), client.height()))) {
241 qCritical(RabbitVNC, "FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
242 r.width(), r.height(), r.tl.x, r.tl.y,
243 client.width(), client.height());
244 safeRect = r.intersect(rfb::Rect(0, 0, client.width(), client.height()));
245 } else {
246 safeRect = r;
247 }
248
249 // Just update the requested region.
250 // Framebuffer update will be sent a bit later, see processMessages().
251 rfb::Region reqRgn(safeRect);
252 if (!incremental || !continuousUpdates)
253 requested.assign_union(reqRgn);
254
255 if (!incremental) {
256 // Non-incremental update - treat as if area requested has changed
257 m_Updates.add_changed(reqRgn);
258
259 // And send the screen layout to the client (which, unlike the
260 // framebuffer dimensions, the client doesn't get during init)
261 if (client.supportsEncoding(rfb::pseudoEncodingExtendedDesktopSize))
262 writer()->writeDesktopSize(rfb::reasonServer);
263
264 // We do not send a DesktopSize since it only contains the
265 // framebuffer size (which the client already should know) and
266 // because some clients don't handle extra DesktopSize events
267 // very well.
268 }
269}
270
271void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
272{
273 qDebug(RabbitVNC, "fence: flags:%d,len:%d", flags, len);
274 rdr::U8 type;
275
276 if (flags & rfb::fenceFlagRequest) {
277 if (flags & rfb::fenceFlagSyncNext) {
278 pendingSyncFence = true;
279
280 fenceFlags = flags & (rfb::fenceFlagBlockBefore | rfb::fenceFlagBlockAfter | rfb::fenceFlagSyncNext);
281 fenceDataLen = len;
282 delete [] fenceData;
283 fenceData = NULL;
284 if (len > 0) {
285 fenceData = new char[len];
286 memcpy(fenceData, data, len);
287 }
288
289 return;
290 }
291
292 // We handle everything synchronously so we trivially honor these modes
293 flags = flags & (rfb::fenceFlagBlockBefore | rfb::fenceFlagBlockAfter);
294 if(writer())
295 writer()->writeFence(flags, len, data);
296 return;
297 }
298
299 if (len < 1)
300 qCritical(RabbitVNC, "Fence response of unexpected size received");
301
302 type = data[0];
303
304 switch (type) {
305 case 0:
306 // Initial dummy fence;
307 break;
308 case 1:
309 //congestion.gotPong();
310 break;
311 default:
312 qCritical(RabbitVNC) << "Fence response of unexpected type received";
313 }
314}
315
316void CConnection::enableContinuousUpdates(bool enable, int x, int y, int w, int h)
317{
318 qDebug(RabbitVNC, "enableContinuousUpdates: %d, %d,%d,%d,%d",
319 enable, x,y,w,h);
320 //SConnection::enableContinuousUpdates(enable, x, y, w, h);
321
322 rfb::Rect rect;
323
324 if (!client.supportsFence() || !client.supportsContinuousUpdates())
325 throw rdr::Exception("Client tried to enable continuous updates when not allowed");
326
327 continuousUpdates = enable;
328
329 rect.setXYWH(x, y, w, h);
330 cuRegion.reset(rect);
331
332 if (enable) {
333 requested.clear();
334 } else {
335 writer()->writeEndOfContinuousUpdates();
336 }
337}
338
339void CConnection::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
340{
341 qDebug(RabbitVNC, "keysym:%d;keycode:%d;down:%d", keysym, keycode, down);
342 if(m_InputDevice)
343 m_InputDevice->KeyEvent(keysym, keycode, down);
344}
345
346void CConnection::pointerEvent(const rfb::Point &pos, int buttonMask)
347{
348 //qDebug(RabbitVNC, "pos:%d,%d;button:%d", pos.x, pos.y, buttonMask);
349 CInputDevice::MouseButtons button;
350 if(buttonMask & 0x1)
351 button |= CInputDevice::LeftButton;
352 if(buttonMask & 0x2)
353 button |= CInputDevice::MouseButton::MiddleButton;
354 if(buttonMask & 0x4)
355 button |= CInputDevice::MouseButton::RightButton;
356 if(buttonMask & 0x8)
357 button |= CInputDevice::MouseButton::UWheelButton;
358 if(buttonMask & 0x10)
359 button |= CInputDevice::MouseButton::DWheelButton;
360 if(buttonMask & 0x20)
361 button |= CInputDevice::MouseButton::LWheelButton;
362 if(buttonMask & 0x40)
363 button |= CInputDevice::MouseButton::RWheelButton;
364
365 if(m_InputDevice)
366 m_InputDevice->MouseEvent(button, QPoint(pos.x, pos.y));
367}
368
369void CConnection::clientCutText(const char *str)
370{
371 qDebug(RabbitVNC, "cut text:%s", str);
372}
373
374QSharedPointer<rfb::PixelBuffer> CConnection::GetBufferFromQImage(QImage &img)
375{
376 if(img.isNull())
377 return nullptr;
378
379 QSharedPointer<rfb::PixelBuffer> pb(
380 new rfb::FullFramePixelBuffer(m_PixelFormat,
381 img.width(),
382 img.height(),
383 img.bits(),
384 img.bytesPerLine()
385 / (m_PixelFormat.bpp / 8)));
386 return pb;
387}
388
389void CConnection::writeNoDataUpdate()
390{
391// if (!writer()->needNoDataUpdate())
392// return;
393
394 writer()->writeNoDataUpdate();
395
396 // Make sure no data update is sent until next request
397 //requested.clear();
398}
399
400void CConnection::writeDataUpdate(QImage img, QRect rect)
401{
402 rfb::Region req;
403 rfb::UpdateInfo ui;
404 const rfb::RenderedCursor *cursor = nullptr;
405
406 if(!writer()) return;
407
408 // See what the client has requested (if anything)
409 if (continuousUpdates)
410 req = cuRegion.union_(requested);
411 else
412 req = requested;
413
414 if (req.is_empty())
415 return;
416
417 if(img.isNull())
418 return;
419
420 // Get the lists of updates. Prior to exporting the data to the `ui' object,
421 // getUpdateInfo() will normalize the `updates' object such way that its
422 // `changed' and `copied' regions would not intersect.
423 m_Updates.getUpdateInfo(&ui, req);
424
425 QSharedPointer<rfb::PixelBuffer> buffer = GetBufferFromQImage(img);
426 m_EncodeManager.writeUpdate(ui, buffer.data(), cursor);
427
428}
429
430void CConnection::slotDesktopUpdate(QImage img, QRect rect)
431{
432 //qDebug(RabbitVNC) << "Update screen";
433 if(img.isNull() || !writer())
434 {
435 qCritical(RabbitVNC) << "Image is null";
436 return;
437 }
438
439 writeDataUpdate(img, rect);
440}