Warning, file /network/krfb/krfb/rfbserver.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 Copyright (C) 2009-2010 Collabora Ltd <info@collabora.co.uk> 0003 @author George Goldberg <george.goldberg@collabora.co.uk> 0004 @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk> 0005 Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it> 0006 0007 This program is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This program is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU Lesser General Public License 0018 along with this program. If not, see <http://www.gnu.org/licenses/>. 0019 */ 0020 #include "rfbserver.h" 0021 #include "rfbservermanager.h" 0022 #include "krfbdebug.h" 0023 #include <QSocketNotifier> 0024 #include <QApplication> 0025 #include <QClipboard> 0026 #include <QPointer> 0027 #include <QX11Info> 0028 0029 struct RfbServer::Private 0030 { 0031 QByteArray listeningAddress; 0032 int listeningPort; 0033 bool passwordRequired; 0034 rfbScreenInfoPtr screen; 0035 QPointer<QSocketNotifier> ipv4notifier; 0036 QPointer<QSocketNotifier> ipv6notifier; 0037 }; 0038 0039 RfbServer::RfbServer(QObject *parent) 0040 : QObject(parent), d(new Private) 0041 { 0042 d->listeningAddress = "0.0.0.0"; 0043 d->listeningPort = 0; 0044 d->passwordRequired = true; 0045 d->screen = nullptr; 0046 0047 RfbServerManager::instance()->registerServer(this); 0048 } 0049 0050 RfbServer::~RfbServer() 0051 { 0052 if (d->screen) { 0053 rfbScreenCleanup(d->screen); 0054 } 0055 delete d; 0056 0057 RfbServerManager::instance()->unregisterServer(this); 0058 } 0059 0060 QByteArray RfbServer::listeningAddress() const 0061 { 0062 return d->listeningAddress; 0063 } 0064 0065 int RfbServer::listeningPort() const 0066 { 0067 return d->listeningPort; 0068 } 0069 0070 bool RfbServer::passwordRequired() const 0071 { 0072 return d->passwordRequired; 0073 } 0074 0075 void RfbServer::setListeningAddress(const QByteArray& address) 0076 { 0077 d->listeningAddress = address; 0078 } 0079 0080 void RfbServer::setListeningPort(int port) 0081 { 0082 d->listeningPort = port; 0083 } 0084 0085 void RfbServer::setPasswordRequired(bool passwordRequired) 0086 { 0087 d->passwordRequired = passwordRequired; 0088 } 0089 0090 bool RfbServer::start() 0091 { 0092 if (!d->screen) { 0093 d->screen = RfbServerManager::instance()->newScreen(); 0094 if (!d->screen) { 0095 qCDebug(KRFB) << "Unable to get rbfserver screen"; 0096 return false; 0097 } 0098 0099 // server hooks 0100 d->screen->screenData = this; 0101 d->screen->newClientHook = newClientHook; 0102 d->screen->kbdAddEvent = keyboardHook; 0103 d->screen->ptrAddEvent = pointerHook; 0104 d->screen->passwordCheck = passwordCheck; 0105 d->screen->setXCutText = clipboardHook; 0106 } else { 0107 //if we already have a screen, stop listening first 0108 rfbShutdownServer(d->screen, false); 0109 } 0110 0111 if (listeningAddress() != "0.0.0.0") { 0112 strncpy(d->screen->thisHost, listeningAddress().constData(), 254); 0113 } 0114 0115 if (listeningPort() == 0) { 0116 d->screen->autoPort = 1; 0117 } 0118 0119 d->screen->port = listeningPort(); 0120 d->screen->ipv6port = listeningPort(); 0121 0122 // Disable/Enable password checking 0123 if (passwordRequired()) { 0124 d->screen->authPasswdData = (void *)1; 0125 } else { 0126 d->screen->authPasswdData = (void *)nullptr; 0127 } 0128 0129 qCDebug(KRFB) << "Starting server. Listen port:" << listeningPort() 0130 << "Listen Address:" << listeningAddress() 0131 << "Password enabled:" << passwordRequired(); 0132 0133 rfbInitServer(d->screen); 0134 0135 if (!rfbIsActive(d->screen)) { 0136 qCDebug(KRFB) << "Failed to start server"; 0137 rfbShutdownServer(d->screen, false); 0138 return false; 0139 }; 0140 0141 d->ipv4notifier = new QSocketNotifier(d->screen->listenSock, QSocketNotifier::Read, this); 0142 connect(d->ipv4notifier, &QSocketNotifier::activated, this, &RfbServer::onListenSocketActivated); 0143 if (d->screen->listen6Sock > 0) { 0144 // we're also listening on additional IPv6 socket, get events from there 0145 d->ipv6notifier = new QSocketNotifier(d->screen->listen6Sock, QSocketNotifier::Read, this); 0146 connect(d->ipv6notifier, &QSocketNotifier::activated, this, &RfbServer::onListenSocketActivated); 0147 } 0148 0149 if (QX11Info::isPlatformX11()) { 0150 connect(QApplication::clipboard(), &QClipboard::dataChanged, 0151 this, &RfbServer::krfbSendServerCutText); 0152 } 0153 0154 return true; 0155 } 0156 0157 void RfbServer::stop() 0158 { 0159 if (d->screen) { 0160 rfbShutdownServer(d->screen, true); 0161 for (auto notifier : {d->ipv4notifier, d->ipv6notifier}) { 0162 if (notifier) { 0163 notifier->setEnabled(false); 0164 notifier->deleteLater(); 0165 } 0166 } 0167 } 0168 } 0169 0170 void RfbServer::updateFrameBuffer(char *fb, int width, int height, int depth) 0171 { 0172 int bpp = depth >> 3; 0173 0174 if (bpp != 1 && bpp != 2 && bpp != 4) { 0175 bpp = 4; 0176 } 0177 0178 rfbNewFramebuffer(d->screen, fb, width, height, 8, 3, bpp); 0179 } 0180 0181 void RfbServer::updateScreen(const QList<QRect> & modifiedTiles) 0182 { 0183 if (d->screen) { 0184 QList<QRect>::const_iterator it = modifiedTiles.constBegin(); 0185 for(; it != modifiedTiles.constEnd(); ++it) { 0186 rfbMarkRectAsModified(d->screen, it->x(), it->y(), it->right(), it->bottom()); 0187 } 0188 } 0189 } 0190 0191 /* 0192 * Code copied from vino's bundled libvncserver: 0193 * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. 0194 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 0195 * License: GPL v2 or later 0196 */ 0197 void krfb_rfbSetCursorPosition(rfbScreenInfoPtr screen, rfbClientPtr client, int x, int y) 0198 { 0199 rfbClientIteratorPtr iterator; 0200 rfbClientPtr cl; 0201 0202 if (x == screen->cursorX || y == screen->cursorY) 0203 return; 0204 0205 LOCK(screen->cursorMutex); 0206 screen->cursorX = x; 0207 screen->cursorY = y; 0208 UNLOCK(screen->cursorMutex); 0209 0210 /* Inform all clients about this cursor movement. */ 0211 iterator = rfbGetClientIterator(screen); 0212 while ((cl = rfbClientIteratorNext(iterator)) != nullptr) { 0213 cl->cursorWasMoved = true; 0214 } 0215 rfbReleaseClientIterator(iterator); 0216 0217 /* The cursor was moved by this client, so don't send CursorPos. */ 0218 if (client) { 0219 client->cursorWasMoved = false; 0220 } 0221 } 0222 0223 void RfbServer::updateCursorPosition(const QPoint & position) 0224 { 0225 if (d->screen) { 0226 krfb_rfbSetCursorPosition(d->screen, nullptr, position.x(), position.y()); 0227 } 0228 } 0229 0230 void RfbServer::krfbSendServerCutText() 0231 { 0232 if(d->screen) { 0233 QString text = QApplication::clipboard()->text(); 0234 rfbSendServerCutText(d->screen, 0235 text.toLocal8Bit().data(),text.length()); 0236 } 0237 } 0238 0239 void RfbServer::onListenSocketActivated() 0240 { 0241 rfbProcessNewConnection(d->screen); 0242 } 0243 0244 void RfbServer::pendingClientFinished(RfbClient *client) 0245 { 0246 //qDebug(); 0247 if (client) { 0248 RfbServerManager::instance()->addClient(client); 0249 client->getRfbClientPtr()->clientGoneHook = clientGoneHook; 0250 } 0251 } 0252 0253 //static 0254 rfbNewClientAction RfbServer::newClientHook(rfbClientPtr cl) 0255 { 0256 //qDebug() << "New client"; 0257 auto server = static_cast<RfbServer*>(cl->screen->screenData); 0258 0259 PendingRfbClient *pendingClient = server->newClient(cl); 0260 connect(pendingClient, &PendingRfbClient::finished, 0261 server, &RfbServer::pendingClientFinished); 0262 0263 return RFB_CLIENT_ON_HOLD; 0264 } 0265 0266 //static 0267 void RfbServer::clientGoneHook(rfbClientPtr cl) 0268 { 0269 //qDebug() << "client gone"; 0270 auto client = static_cast<RfbClient*>(cl->clientData); 0271 0272 RfbServerManager::instance()->removeClient(client); 0273 client->deleteLater(); 0274 } 0275 0276 //static 0277 rfbBool RfbServer::passwordCheck(rfbClientPtr cl, const char *encryptedPassword, int len) 0278 { 0279 auto client = static_cast<PendingRfbClient*>(cl->clientData); 0280 Q_ASSERT(client); 0281 return client->checkPassword(QByteArray::fromRawData(encryptedPassword, len)); 0282 } 0283 0284 //static 0285 void RfbServer::keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) 0286 { 0287 auto client = static_cast<RfbClient*>(cl->clientData); 0288 client->handleKeyboardEvent(down ? true : false, keySym); 0289 } 0290 0291 //static 0292 void RfbServer::pointerHook(int bm, int x, int y, rfbClientPtr cl) 0293 { 0294 auto client = static_cast<RfbClient*>(cl->clientData); 0295 client->handleMouseEvent(bm, x, y); 0296 } 0297 0298 //static 0299 void RfbServer::clipboardHook(char *str, int len, rfbClientPtr /*cl*/) 0300 { 0301 QApplication::clipboard()->setText(QString::fromLocal8Bit(str,len)); 0302 }