aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer/CConn.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vncviewer/CConn.cxx')
-rw-r--r--vncviewer/CConn.cxx354
1 files changed, 176 insertions, 178 deletions
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index f8e80429..da99c8f1 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -27,17 +27,21 @@
#include <unistd.h>
#endif
-#include <rdr/Exception.h>
+#include <core/LogWriter.h>
+#include <core/Timer.h>
+#include <core/string.h>
+#include <core/time.h>
+
+#include <rdr/FdInStream.h>
+#include <rdr/FdOutStream.h>
#include <rfb/CMsgWriter.h>
#include <rfb/CSecurity.h>
#include <rfb/Exception.h>
-#include <rfb/Hostname.h>
-#include <rfb/LogWriter.h>
#include <rfb/Security.h>
-#include <rfb/screenTypes.h>
#include <rfb/fenceTypes.h>
-#include <rfb/Timer.h>
+#include <rfb/screenTypes.h>
+
#include <network/TcpSocket.h>
#ifndef WIN32
#include <network/UnixSocket.h>
@@ -58,29 +62,27 @@
#include "win32.h"
#endif
-using namespace rfb;
-
-static rfb::LogWriter vlog("CConn");
+static core::LogWriter vlog("CConn");
// 8 colours (1 bit per component)
-static const PixelFormat verylowColourPF(8, 3,false, true,
- 1, 1, 1, 2, 1, 0);
+static const rfb::PixelFormat verylowColourPF(8, 3,false, true,
+ 1, 1, 1, 2, 1, 0);
// 64 colours (2 bits per component)
-static const PixelFormat lowColourPF(8, 6, false, true,
- 3, 3, 3, 4, 2, 0);
+static const rfb::PixelFormat lowColourPF(8, 6, false, true,
+ 3, 3, 3, 4, 2, 0);
// 256 colours (2-3 bits per component)
-static const PixelFormat mediumColourPF(8, 8, false, true,
- 7, 7, 3, 5, 2, 0);
+static const rfb::PixelFormat mediumColourPF(8, 8, false, true,
+ 7, 7, 3, 5, 2, 0);
// Time new bandwidth estimates are weighted against (in ms)
static const unsigned bpsEstimateWindow = 1000;
-CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)
- : serverPort(0), desktop(nullptr), updateCount(0), pixelCount(0),
+CConn::CConn()
+ : serverPort(0), sock(nullptr), desktop(nullptr),
+ updateCount(0), pixelCount(0),
lastServerEncoding((unsigned int)-1), bpsEstimate(20000000)
{
setShared(::shared);
- sock = socket;
supportsLocalCursor = true;
supportsCursorPosition = true;
@@ -93,6 +95,61 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)
if (!noJpeg)
setQualityLevel(::qualityLevel);
+ OptionsDialog::addCallback(handleOptions, this);
+}
+
+CConn::~CConn()
+{
+ close();
+
+ OptionsDialog::removeCallback(handleOptions);
+ Fl::remove_timeout(handleUpdateTimeout, this);
+
+ if (desktop)
+ delete desktop;
+
+ if (sock) {
+ struct timeval now;
+
+ sock->shutdown();
+
+ // Do a graceful close by waiting for the peer (up to 250 ms)
+ // FIXME: should do this asynchronously
+ gettimeofday(&now, nullptr);
+ while (core::msSince(&now) < 250) {
+ bool done;
+
+ done = false;
+ while (true) {
+ try {
+ sock->inStream().skip(sock->inStream().avail());
+ if (!sock->inStream().hasData(1))
+ break;
+ } catch (std::exception&) {
+ done = true;
+ break;
+ }
+ }
+
+ if (done)
+ break;
+
+ #ifdef WIN32
+ Sleep(10);
+ #else
+ usleep(10000);
+ #endif
+ }
+
+ Fl::remove_fd(sock->getFd());
+
+ delete sock;
+ }
+}
+
+void CConn::connect(const char* vncServerName, network::Socket* socket)
+{
+ sock = socket;
if(sock == nullptr) {
try {
#ifndef WIN32
@@ -103,7 +160,7 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)
} else
#endif
{
- getHostAndPort(vncServerName, &serverHost, &serverPort);
+ network::getHostAndPort(vncServerName, &serverHost, &serverPort);
sock = new network::TcpSocket(serverHost.c_str(), serverPort);
vlog.info(_("Connected to host %s port %d"),
@@ -123,23 +180,6 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)
setStreams(&sock->inStream(), &sock->outStream());
initialiseProtocol();
-
- OptionsDialog::addCallback(handleOptions, this);
-}
-
-CConn::~CConn()
-{
- close();
-
- OptionsDialog::removeCallback(handleOptions);
- Fl::remove_timeout(handleUpdateTimeout, this);
-
- if (desktop)
- delete desktop;
-
- if (sock)
- Fl::remove_fd(sock->getFd());
- delete sock;
}
std::string CConn::connectionInfo()
@@ -148,46 +188,41 @@ std::string CConn::connectionInfo()
char pfStr[100];
- infoText += format(_("Desktop name: %.80s"), server.name());
+ infoText += core::format(_("Desktop name: %.80s"), server.name());
infoText += "\n";
- infoText += format(_("Host: %.80s port: %d"),
- serverHost.c_str(), serverPort);
+ infoText += core::format(_("Host: %.80s port: %d"),
+ serverHost.c_str(), serverPort);
infoText += "\n";
- infoText += format(_("Size: %d x %d"),
- server.width(), server.height());
+ infoText += core::format(_("Size: %d x %d"),
+ server.width(), server.height());
infoText += "\n";
// TRANSLATORS: Will be filled in with a string describing the
// protocol pixel format in a fairly language neutral way
server.pf().print(pfStr, 100);
- infoText += format(_("Pixel format: %s"), pfStr);
+ infoText += core::format(_("Pixel format: %s"), pfStr);
infoText += "\n";
- // TRANSLATORS: Similar to the earlier "Pixel format" string
- serverPF.print(pfStr, 100);
- infoText += format(_("(server default %s)"), pfStr);
+ infoText += core::format(_("Requested encoding: %s"),
+ rfb::encodingName(getPreferredEncoding()));
infoText += "\n";
- infoText += format(_("Requested encoding: %s"),
- encodingName(getPreferredEncoding()));
+ infoText += core::format(_("Last used encoding: %s"),
+ rfb::encodingName(lastServerEncoding));
infoText += "\n";
- infoText += format(_("Last used encoding: %s"),
- encodingName(lastServerEncoding));
+ infoText += core::format(_("Line speed estimate: %d kbit/s"),
+ (int)(bpsEstimate / 1000));
infoText += "\n";
- infoText += format(_("Line speed estimate: %d kbit/s"),
- (int)(bpsEstimate / 1000));
+ infoText += core::format(_("Protocol version: %d.%d"),
+ server.majorVersion, server.minorVersion);
infoText += "\n";
- infoText += format(_("Protocol version: %d.%d"),
- server.majorVersion, server.minorVersion);
- infoText += "\n";
-
- infoText += format(_("Security method: %s"),
- secTypeName(csecurity->getType()));
+ infoText += core::format(_("Security method: %s"),
+ rfb::secTypeName(csecurity->getType()));
infoText += "\n";
return infoText;
@@ -236,7 +271,7 @@ void CConn::socketEvent(FL_SOCKET fd, void *data)
// Make sure that the FLTK handling and the timers gets some CPU
// time in case of back to back messages
Fl::check();
- Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
// Also check if we need to stop reading and terminate
if (should_disconnect())
@@ -282,7 +317,7 @@ void CConn::resetPassword()
////////////////////// CConnection callback methods //////////////////////
-bool CConn::showMsgBox(MsgBoxFlags flags, const char *title,
+bool CConn::showMsgBox(rfb::MsgBoxFlags flags, const char *title,
const char *text)
{
return dlg.showMsgBox(flags, title, text);
@@ -304,46 +339,29 @@ void CConn::initDone()
if (server.beforeVersion(3, 8) && autoSelect)
fullColour.setParam(true);
- serverPF = server.pf();
-
- desktop = new DesktopWindow(server.width(), server.height(),
- server.name(), serverPF, this);
+ desktop = new DesktopWindow(server.width(), server.height(), this);
fullColourPF = desktop->getPreferredPF();
// Force a switch to the format and encoding we'd like
+ updateEncoding();
updatePixelFormat();
- int encNum = encodingNum(::preferredEncoding);
- if (encNum != -1)
- setPreferredEncoding(encNum);
-}
-
-// setDesktopSize() is called when the desktop size changes (including when
-// it is set initially).
-void CConn::setDesktopSize(int w, int h)
-{
- CConnection::setDesktopSize(w,h);
- resizeFramebuffer();
}
-// setExtendedDesktopSize() is a more advanced version of setDesktopSize()
void CConn::setExtendedDesktopSize(unsigned reason, unsigned result,
- int w, int h, const rfb::ScreenSet& layout)
+ int w, int h,
+ const rfb::ScreenSet& layout)
{
CConnection::setExtendedDesktopSize(reason, result, w, h, layout);
- if ((reason == reasonClient) && (result != resultSuccess)) {
- vlog.error(_("SetDesktopSize failed: %d"), result);
- return;
- }
-
- resizeFramebuffer();
+ if (reason == rfb::reasonClient)
+ desktop->setDesktopSizeDone(result);
}
// setName() is called when the desktop name changes
void CConn::setName(const char* name)
{
CConnection::setName(name);
- desktop->setName(name);
+ desktop->updateCaption();
}
// framebufferUpdateStart() is called at the beginning of an update.
@@ -396,28 +414,25 @@ void CConn::framebufferUpdateEnd()
desktop->updateWindow();
// Compute new settings based on updated bandwidth values
- if (autoSelect)
- autoSelectFormatAndEncoding();
+ if (autoSelect) {
+ updateEncoding();
+ updateQualityLevel();
+ updatePixelFormat();
+ }
}
// The rest of the callbacks are fairly self-explanatory...
-void CConn::setColourMapEntries(int /*firstColour*/, int /*nColours*/,
- uint16_t* /*rgbs*/)
-{
- vlog.error(_("Invalid SetColourMapEntries from server!"));
-}
-
void CConn::bell()
{
fl_beep();
}
-bool CConn::dataRect(const Rect& r, int encoding)
+bool CConn::dataRect(const core::Rect& r, int encoding)
{
bool ret;
- if (encoding != encodingCopyRect)
+ if (encoding != rfb::encodingCopyRect)
lastServerEncoding = encoding;
ret = CConnection::dataRect(r, encoding);
@@ -428,28 +443,17 @@ bool CConn::dataRect(const Rect& r, int encoding)
return ret;
}
-void CConn::setCursor(int width, int height, const Point& hotspot,
+void CConn::setCursor(int width, int height, const core::Point& hotspot,
const uint8_t* data)
{
- desktop->setCursor(width, height, hotspot, data);
-}
+ CConnection::setCursor(width, height, hotspot, data);
-void CConn::setCursorPos(const Point& pos)
-{
- desktop->setCursorPos(pos);
+ desktop->setCursor();
}
-void CConn::fence(uint32_t flags, unsigned len, const uint8_t data[])
+void CConn::setCursorPos(const core::Point& pos)
{
- CMsgHandler::fence(flags, len, data);
-
- if (flags & fenceFlagRequest) {
- // We handle everything synchronously so we trivially honor these modes
- flags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter);
-
- writer()->writeFence(flags, len, data);
- return;
- }
+ desktop->setCursorPos(pos);
}
void CConn::setLEDState(unsigned int state)
@@ -482,44 +486,59 @@ void CConn::resizeFramebuffer()
desktop->resizeFramebuffer(server.width(), server.height());
}
-// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
-// to the connection speed:
-//
-// First we wait for at least one second of bandwidth measurement.
-//
-// Above 16Mbps (i.e. LAN), we choose the second highest JPEG quality,
-// which should be perceptually lossless.
-//
-// If the bandwidth is below that, we choose a more lossy JPEG quality.
-//
-// If the bandwidth drops below 256 Kbps, we switch to palette mode.
-//
-// Note: The system here is fairly arbitrary and should be replaced
-// with something more intelligent at the server end.
-//
-void CConn::autoSelectFormatAndEncoding()
+void CConn::updateEncoding()
+{
+ int encNum;
+
+ if (autoSelect)
+ encNum = rfb::encodingTight;
+ else
+ encNum = rfb::encodingNum(::preferredEncoding.getValueStr().c_str());
+
+ if (encNum != -1)
+ setPreferredEncoding(encNum);
+}
+
+void CConn::updateCompressLevel()
{
- bool newFullColour = fullColour;
- int newQualityLevel = ::qualityLevel;
+ if (customCompressLevel)
+ setCompressLevel(::compressLevel);
+ else
+ setCompressLevel(-1);
+}
- // Always use Tight
- setPreferredEncoding(encodingTight);
+void CConn::updateQualityLevel()
+{
+ int newQualityLevel;
+
+ if (noJpeg)
+ newQualityLevel = -1;
+ else if (!autoSelect)
+ newQualityLevel = ::qualityLevel;
+ else {
+ // Above 16Mbps (i.e. LAN), we choose the second highest JPEG
+ // quality, which should be perceptually lossless. If the bandwidth
+ // is below that, we choose a more lossy JPEG quality.
- // Select appropriate quality level
- if (!noJpeg) {
if (bpsEstimate > 16000000)
newQualityLevel = 8;
else
newQualityLevel = 6;
- if (newQualityLevel != ::qualityLevel) {
+ if (newQualityLevel != getQualityLevel()) {
vlog.info(_("Throughput %d kbit/s - changing to quality %d"),
(int)(bpsEstimate/1000), newQualityLevel);
- ::qualityLevel.setParam(newQualityLevel);
- setQualityLevel(newQualityLevel);
}
}
+ setQualityLevel(newQualityLevel);
+}
+
+void CConn::updatePixelFormat()
+{
+ bool useFullColour;
+ rfb::PixelFormat pf;
+
if (server.beforeVersion(3, 8)) {
// Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
// cursors "asynchronously". If this happens in the middle of a
@@ -530,28 +549,23 @@ void CConn::autoSelectFormatAndEncoding()
// old servers.
return;
}
-
- // Select best color level
- newFullColour = (bpsEstimate > 256000);
- if (newFullColour != fullColour) {
- if (newFullColour)
- vlog.info(_("Throughput %d kbit/s - full color is now enabled"),
- (int)(bpsEstimate/1000));
- else
- vlog.info(_("Throughput %d kbit/s - full color is now disabled"),
- (int)(bpsEstimate/1000));
- fullColour.setParam(newFullColour);
- updatePixelFormat();
- }
-}
-// requestNewUpdate() requests an update from the server, having set the
-// format and encoding appropriately.
-void CConn::updatePixelFormat()
-{
- PixelFormat pf;
+ useFullColour = fullColour;
+
+ // If the bandwidth drops below 256 Kbps, we switch to palette mode.
+ if (autoSelect) {
+ useFullColour = (bpsEstimate > 256000);
+ if (useFullColour != (server.pf() == fullColourPF)) {
+ if (useFullColour)
+ vlog.info(_("Throughput %d kbit/s - full color is now enabled"),
+ (int)(bpsEstimate/1000));
+ else
+ vlog.info(_("Throughput %d kbit/s - full color is now disabled"),
+ (int)(bpsEstimate/1000));
+ }
+ }
- if (fullColour) {
+ if (useFullColour) {
pf = fullColourPF;
} else {
if (lowColourLevel == 0)
@@ -562,37 +576,21 @@ void CConn::updatePixelFormat()
pf = mediumColourPF;
}
- char str[256];
- pf.print(str, 256);
- vlog.info(_("Using pixel format %s"),str);
- setPF(pf);
+ if (pf != server.pf()) {
+ char str[256];
+ pf.print(str, 256);
+ vlog.info(_("Using pixel format %s"),str);
+ setPF(pf);
+ }
}
void CConn::handleOptions(void *data)
{
CConn *self = (CConn*)data;
- // Checking all the details of the current set of encodings is just
- // a pain. Assume something has changed, as resending the encoding
- // list is cheap. Avoid overriding what the auto logic has selected
- // though.
- if (!autoSelect) {
- int encNum = encodingNum(::preferredEncoding);
-
- if (encNum != -1)
- self->setPreferredEncoding(encNum);
- }
-
- if (customCompressLevel)
- self->setCompressLevel(::compressLevel);
- else
- self->setCompressLevel(-1);
-
- if (!noJpeg && !autoSelect)
- self->setQualityLevel(::qualityLevel);
- else
- self->setQualityLevel(-1);
-
+ self->updateEncoding();
+ self->updateCompressLevel();
+ self->updateQualityLevel();
self->updatePixelFormat();
}