Beispiel #1
0
void
CClient::connect()
{
	if (m_stream != NULL) {
		return;
	}
	if (m_suspended) {
		m_connectOnResume = true;
		return;
	}

	try {
		// resolve the server hostname.  do this every time we connect
		// in case we couldn't resolve the address earlier or the address
		// has changed (which can happen frequently if this is a laptop
		// being shuttled between various networks).  patch by Brent
		// Priddy.
		m_serverAddress.resolve();
		
		// m_serverAddress will be null if the hostname address is not reolved
		if (m_serverAddress.getAddress() != NULL) {
		  // to help users troubleshoot, show server host name (issue: 60)
		  LOG((CLOG_NOTE "connecting to '%s': %s:%i", 
		  m_serverAddress.getHostname().c_str(),
		  ARCH->addrToString(m_serverAddress.getAddress()).c_str(),
		  m_serverAddress.getPort()));
		}

		// create the socket
		IDataSocket* socket = m_socketFactory->create();

		// filter socket messages, including a packetizing filter
		m_stream = socket;
		if (m_streamFilterFactory != NULL) {
			m_stream = m_streamFilterFactory->create(m_stream, true);
		}
		m_stream = new CPacketStreamFilter(m_events, m_stream, true);

		if (m_crypto.m_mode != kDisabled) {
			m_cryptoStream = new CCryptoStream(
				m_events, m_stream, m_crypto, true);
			m_stream = m_cryptoStream;
		}

		// connect
		LOG((CLOG_DEBUG1 "connecting to server"));
		setupConnecting();
		setupTimer();
		socket->connect(m_serverAddress);
	}
	catch (XBase& e) {
		cleanupTimer();
		cleanupConnecting();
		delete m_stream;
		m_stream = NULL;
		LOG((CLOG_DEBUG1 "connection failed"));
		sendConnectionFailedEvent(e.what());
		return;
	}
}
Beispiel #2
0
void
Client::handleDisconnected(const Event&, void*)
{
	cleanupTimer();
	cleanupScreen();
	cleanupConnection();
	LOG((CLOG_DEBUG1 "disconnected"));
	sendEvent(m_events->forClient().disconnected(), NULL);
}
Beispiel #3
0
void
Client::handleOutputError(const Event&, void*)
{
	cleanupTimer();
	cleanupScreen();
	cleanupConnection();
	LOG((CLOG_WARN "error sending to server"));
	sendEvent(m_events->forClient().disconnected(), NULL);
}
Beispiel #4
0
void
CClient::handleDisconnected(const CEvent&, void*)
{
	cleanupTimer();
	cleanupScreen();
	cleanupConnection();
	LOG((CLOG_DEBUG1 "disconnected"));
	sendEvent(getDisconnectedEvent(), NULL);
}
Beispiel #5
0
void
CClient::handleOutputError(const CEvent&, void*)
{
	cleanupTimer();
	cleanupScreen();
	cleanupConnection();
	LOG((CLOG_WARN "error sending to server"));
	sendEvent(getDisconnectedEvent(), NULL);
}
Beispiel #6
0
void
Client::handleConnectTimeout(const Event&, void*)
{
	cleanupTimer();
	cleanupConnecting();
	cleanupConnection();
	cleanupStream();
	LOG((CLOG_DEBUG1 "connection timed out"));
	sendConnectionFailedEvent("Timed out");
}
Beispiel #7
0
void
CClient::handleConnectTimeout(const CEvent&, void*)
{
	cleanupTimer();
	cleanupConnecting();
	cleanupConnection();
	delete m_stream;
	m_stream = NULL;
	LOG((CLOG_DEBUG1 "connection timed out"));
	sendConnectionFailedEvent("Timed out");
}
Beispiel #8
0
void
Client::handleHello(const Event&, void*)
{
	SInt16 major, minor;
	if (!ProtocolUtil::readf(m_stream, kMsgHello, &major, &minor)) {
		sendConnectionFailedEvent("Protocol error from server, check encryption settings");
		cleanupTimer();
		cleanupConnection();
		return;
	}

	// check versions
	LOG((CLOG_DEBUG1 "got hello version %d.%d", major, minor));
	if (major < kProtocolMajorVersion ||
		(major == kProtocolMajorVersion && minor < kProtocolMinorVersion)) {
		sendConnectionFailedEvent(XIncompatibleClient(major, minor).what());
		cleanupTimer();
		cleanupConnection();
		return;
	}

	// say hello back
	LOG((CLOG_DEBUG1 "say hello version %d.%d", kProtocolMajorVersion, kProtocolMinorVersion));
	ProtocolUtil::writef(m_stream, kMsgHelloBack,
							kProtocolMajorVersion,
							kProtocolMinorVersion, &m_name);

	// now connected but waiting to complete handshake
	setupScreen();
	cleanupTimer();

	// make sure we process any remaining messages later.  we won't
	// receive another event for already pending messages so we fake
	// one.
	if (m_stream->isReady()) {
		m_events->addEvent(Event(m_events->forIStream().inputReady(),
							m_stream->getEventTarget()));
	}
}
Beispiel #9
0
void
Client::handleConnectionFailed(const Event& event, void*)
{
	IDataSocket::ConnectionFailedInfo* info =
		reinterpret_cast<IDataSocket::ConnectionFailedInfo*>(event.getData());

	cleanupTimer();
	cleanupConnecting();
	cleanupStream();
	LOG((CLOG_DEBUG1 "connection failed"));
	sendConnectionFailedEvent(info->m_what.c_str());
	delete info;
}
Beispiel #10
0
CClient::~CClient()
{
	EVENTQUEUE->removeHandler(IScreen::getSuspendEvent(),
							  getEventTarget());
	EVENTQUEUE->removeHandler(IScreen::getResumeEvent(),
							  getEventTarget());

	cleanupTimer();
	cleanupScreen();
	cleanupConnecting();
	cleanupConnection();
	delete m_socketFactory;
	delete m_streamFilterFactory;
}
Beispiel #11
0
void
Client::disconnect(const char* msg)
{
	m_connectOnResume = false;
	cleanupTimer();
	cleanupScreen();
	cleanupConnecting();
	cleanupConnection();
	if (msg != NULL) {
		sendConnectionFailedEvent(msg);
	}
	else {
		sendEvent(m_events->forClient().disconnected(), NULL);
	}
}
Beispiel #12
0
void HTTPResourceRequest::onTimeout() {
    qDebug() << "Timeout: " << _url << ":" << _reply->isFinished();
    Q_ASSERT(_state == InProgress);
    _reply->disconnect(this);
    _reply->abort();
    _reply->deleteLater();
    _reply = nullptr;

    cleanupTimer();
    
    _result = Timeout;
    _state = Finished;
    emit finished();

    DependencyManager::get<StatTracker>()->incrementStat(STAT_HTTP_REQUEST_FAILED);
}
Beispiel #13
0
Client::~Client()
{
	if (m_mock) {
		return;
	}

	m_events->removeHandler(m_events->forIScreen().suspend(),
							  getEventTarget());
	m_events->removeHandler(m_events->forIScreen().resume(),
							  getEventTarget());

	cleanupTimer();
	cleanupScreen();
	cleanupConnecting();
	cleanupConnection();
	delete m_socketFactory;
}
Beispiel #14
0
void
CClient::connect()
{
	if (m_stream != NULL) {
		return;
	}
	if (m_suspended) {
		m_connectOnResume = true;
		return;
	}

	try {
		// resolve the server hostname.  do this every time we connect
		// in case we couldn't resolve the address earlier or the address
		// has changed (which can happen frequently if this is a laptop
		// being shuttled between various networks).  patch by Brent
		// Priddy.
		m_serverAddress.resolve();

		// create the socket
		IDataSocket* socket = m_socketFactory->create();

		// filter socket messages, including a packetizing filter
		m_stream = socket;
		if (m_streamFilterFactory != NULL) {
			m_stream = m_streamFilterFactory->create(m_stream, true);
		}
		m_stream = new CPacketStreamFilter(m_stream, true);

		// connect
		LOG((CLOG_DEBUG1 "connecting to server"));
		setupConnecting();
		setupTimer();
		socket->connect(m_serverAddress);
	}
	catch (XBase& e) {
		cleanupTimer();
		cleanupConnecting();
		delete m_stream;
		m_stream = NULL;
		LOG((CLOG_DEBUG1 "connection failed"));
		sendConnectionFailedEvent(e.what());
		return;
	}
}
Beispiel #15
0
CClient::~CClient()
{
	// HACK: can't disable dtor with mocks
	if (m_mock)
		return;

	m_eventQueue.removeHandler(IScreen::getSuspendEvent(),
							  getEventTarget());
	m_eventQueue.removeHandler(IScreen::getResumeEvent(),
							  getEventTarget());

	cleanupTimer();
	cleanupScreen();
	cleanupConnecting();
	cleanupConnection();
	delete m_socketFactory;
	delete m_streamFilterFactory;
}
Beispiel #16
0
void HTTPResourceRequest::onRequestFinished() {
    Q_ASSERT(_state == InProgress);
    Q_ASSERT(_reply);

    cleanupTimer();

    // Content-Range headers have the form: 
    //
    //   Content-Range: <unit> <range-start>-<range-end>/<size>
    //   Content-Range: <unit> <range-start>-<range-end>/*
    //   Content-Range: <unit> */<size>
    //
    auto parseContentRangeHeader = [](QString contentRangeHeader) -> std::pair<bool, uint64_t> {
        auto unitRangeParts = contentRangeHeader.split(' ');
        if (unitRangeParts.size() != 2) {
            return { false, 0 };
        }

        auto rangeSizeParts = unitRangeParts[1].split('/');
        if (rangeSizeParts.size() != 2) {
            return { false, 0 };
        }

        auto sizeStr = rangeSizeParts[1];
        if (sizeStr == "*") {
            return { true, 0 };
        } else {
            bool ok;
            auto size = sizeStr.toLong(&ok);
            return { ok, size };
        }
    };

    switch(_reply->error()) {
        case QNetworkReply::NoError:
            _data = _reply->readAll();
            _loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
            _result = Success;

            if (_byteRange.isSet()) {
                auto statusCode = _reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
                if (statusCode == 206) {
                    _rangeRequestSuccessful = true;
                    auto contentRangeHeader = _reply->rawHeader("Content-Range");
                    bool success;
                    uint64_t size;
                    std::tie(success, size) = parseContentRangeHeader(contentRangeHeader);
                    if (success) {
                        _totalSizeOfResource = size;
                    } else {
                        qWarning(networking) << "Error parsing content-range header: " << contentRangeHeader;
                        _totalSizeOfResource = 0;
                    }
                } else {
                    _rangeRequestSuccessful = false;
                    _totalSizeOfResource = _data.size();
                }
            }

            recordBytesDownloadedInStats(STAT_HTTP_RESOURCE_TOTAL_BYTES, _data.size());

            break;

        case QNetworkReply::TimeoutError:
            _result = Timeout;
            break;

        case QNetworkReply::ContentNotFoundError: // Script.include('https://httpbin.org/status/404')
            _result = NotFound;
            break;

        case QNetworkReply::ProtocolInvalidOperationError: // Script.include('https://httpbin.org/status/400')
            _result = InvalidURL;
            break;

        case QNetworkReply::UnknownContentError: // Script.include('QUrl("https://httpbin.org/status/402")')
        case QNetworkReply::ContentOperationNotPermittedError: //Script.include('https://httpbin.org/status/403')
        case QNetworkReply::AuthenticationRequiredError: // Script.include('https://httpbin.org/basic-auth/user/passwd')
            _result = AccessDenied;
            break;

        case QNetworkReply::RemoteHostClosedError:  // Script.include('http://127.0.0.1:22')
        case QNetworkReply::ConnectionRefusedError: // Script.include(http://127.0.0.1:1')
        case QNetworkReply::HostNotFoundError:      // Script.include('http://foo.bar.highfidelity.io')
        case QNetworkReply::ServiceUnavailableError: // Script.include('QUrl("https://httpbin.org/status/503")')
            _result = ServerUnavailable;
            break;

        case QNetworkReply::UnknownServerError: // Script.include('QUrl("https://httpbin.org/status/504")')
        case QNetworkReply::InternalServerError: // Script.include('QUrl("https://httpbin.org/status/500")')
        default:
            qCDebug(networking) << "HTTPResourceRequest error:" << QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(_reply->error());
            _result = Error;
            break;
    }
    _reply->disconnect(this);
    _reply->deleteLater();
    _reply = nullptr;
    
    _state = Finished;
    emit finished();

    auto statTracker = DependencyManager::get<StatTracker>();
    if (_result == Success) {
        statTracker->incrementStat(STAT_HTTP_REQUEST_SUCCESS);

        if (loadedFromCache()) {
            statTracker->incrementStat(STAT_HTTP_REQUEST_CACHE);
        }
    } else {
        statTracker->incrementStat(STAT_HTTP_REQUEST_FAILED);
    }
}