/* ------------------------------------------------------------------------- * BKG NTRIP Server * ------------------------------------------------------------------------- * * Class: bncUploadCaster * * Purpose: Connection to NTRIP Caster * * Author: L. Mervart * * Created: 29-Mar-2011 * * Changes: * * -----------------------------------------------------------------------*/ #include #include "bncuploadcaster.h" #include "bncversion.h" #include "bnccore.h" #include "bnctableitem.h" #include "bncsettings.h" using namespace std; // Constructor //////////////////////////////////////////////////////////////////////////// bncUploadCaster::bncUploadCaster(const QString& mountpoint, const QString& outHost, int outPort, const QString& ntripVersion, const QString& userName, const QString& password, int iRow, int rate) { _mountpoint = mountpoint; _casterOutHost = outHost; _casterOutPort = outPort; _ntripVersion = ntripVersion; (_ntripVersion == "2s") ? _secure = true : _secure = false; _postExtension = ""; _userName = userName; _password = password; _outSocket = 0; _sOpenTrial = 0; _iRow = iRow; _rate = rate; if (_rate < 0) { _rate = 0; } else if (_rate > 60) { _rate = 60; } _isToBeDeleted = false; if (!QSslSocket::supportsSsl()) { BNC_CORE->slotMessage("No SSL support, install OpenSSL run-time libraries", true); deleteSafely(); } if (_ntripVersion != "1") { bncSettings settings; _sslIgnoreErrors = (Qt::CheckState(settings.value("sslIgnoreErrors").toInt()) == Qt::Checked); _proxyHost = settings.value("proxyHost").toString(); _proxyPort = settings.value("proxyPort").toInt(); if (_secure) { _casterOutPort = 443; if (!_proxyHost.isEmpty()) { _postExtension = QString("https://%1:%2").arg(_casterOutHost).arg(_casterOutPort); } } else { if (!_proxyHost.isEmpty()) { _postExtension = QString("http://%1:%2").arg(_casterOutHost).arg(_casterOutPort); } } } connect(this, SIGNAL(newMessage(QByteArray,bool)), BNC_CORE, SLOT(slotMessage(const QByteArray,bool))); if (BNC_CORE->_uploadTableItems.find(_iRow) != BNC_CORE->_uploadTableItems.end()){ connect(this, SIGNAL(newBytes(QByteArray,double)), BNC_CORE->_uploadTableItems.value(iRow), SLOT(slotNewBytes(const QByteArray,double))); } if (BNC_CORE->_uploadEphTableItems.find(_iRow) != BNC_CORE->_uploadEphTableItems.end()){ connect(this, SIGNAL(newBytes(QByteArray,double)), BNC_CORE->_uploadEphTableItems.value(iRow), SLOT(slotNewBytes(const QByteArray,double))); } } // Safe Desctructor //////////////////////////////////////////////////////////////////////////// void bncUploadCaster::deleteSafely() { _isToBeDeleted = true; if (!isRunning()) { delete this; } } // Destructor //////////////////////////////////////////////////////////////////////////// bncUploadCaster::~bncUploadCaster() { if (isRunning()) { wait(); } if (_outSocket) { disconnect(_outSocket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)), this, SLOT(slotProxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*))); delete _outSocket; } } // //////////////////////////////////////////////////////////////////////////// void bncUploadCaster::slotProxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*) { emit newMessage("slotProxyAuthenticationRequired", true); } /* TSL/SSL //////////////////////////////////////////////////////////////////////////// void bncUploadCaster::slotSslErrors(QList errors) { QString msg = "SSL Error\n"; QSslCertificate cert = _outSocket->sslConfiguration().peerCertificate(); if (!cert.isNull()) { msg += QString("Server Certificate Issued by:\n" "%1\n%2\nCannot be verified\n") #if QT_VERSION >= 0x050000 .arg(cert.issuerInfo(QSslCertificate::OrganizationalUnitName).at(0)) .arg(cert.issuerInfo(QSslCertificate::Organization).at(0)); #else .arg(cert.issuerInfo(QSslCertificate::OrganizationalUnitName)) .arg(cert.issuerInfo(QSslCertificate::Organization)); #endif } QListIterator it(errors); while (it.hasNext()) { const QSslError& err = it.next(); msg += "\n" + err.errorString(); } BNC_CORE->slotMessage(msg.toLatin1(), true); if (_sslIgnoreErrors) { _outSocket->ignoreSslErrors(); } else { deleteSafely(); } } */ // Endless Loop //////////////////////////////////////////////////////////////////////////// void bncUploadCaster::run() { while (true) { if (_isToBeDeleted) { QThread::quit(); deleteLater(); return; } open(); if (_outSocket && _outSocket->state() == QAbstractSocket::ConnectedState) { QMutexLocker locker(&_mutex); if (_outBuffer.size() > 0) { if (_ntripVersion == "1") { _outSocket->write(_outBuffer); _outSocket->flush(); } else { QString chunkSize = QString("%1").arg(_outBuffer.size(),0,16,QLatin1Char('0')); QByteArray chunkedData = chunkSize.toLatin1() + "\r\n" + _outBuffer + "\r\n"; _outSocket->write(chunkedData); _outSocket->flush(); } emit newBytes(_mountpoint.toLatin1(), _outBuffer.size()); } } if (_rate == 0) { { QMutexLocker locker(&_mutex); _outBuffer.clear(); } msleep(100); //sleep 0.1 sec } else { sleep(_rate); } } } // Start the Communication with NTRIP Caster //////////////////////////////////////////////////////////////////////////// void bncUploadCaster::open() { if (_mountpoint.isEmpty()) { return; } if (_outSocket != 0) { if (_outSocket->state() == QAbstractSocket::ConnectedState) { return; } else { emit(newMessage("Broadcaster: No connection for " + _mountpoint.toLatin1(), true)); } } delete _outSocket; _outSocket = 0; double minDt = pow(2.0,_sOpenTrial); if (++_sOpenTrial > 4) { _sOpenTrial = 4; } if (_outSocketOpenTime.isValid() && _outSocketOpenTime.secsTo(QDateTime::currentDateTime()) < minDt) { return; } else { _outSocketOpenTime = QDateTime::currentDateTime(); } _outSocket = new QSslSocket(); if (_sslIgnoreErrors) { _outSocket->ignoreSslErrors(); } _outSocket->setProxy(QNetworkProxy::NoProxy); // to prevent the usage of system entries _outHost = _casterOutHost; _outPort = _casterOutPort; if (!_proxyHost.isEmpty()) { _outHost = _proxyHost; _outPort = _proxyPort; connect(_outSocket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)), this, SLOT(slotProxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*))); } const int timeOut = 5000; // 5 seconds if (!_secure) { _outSocket->connectToHost(_outHost, _outPort); if (!_outSocket->waitForConnected(timeOut)) { emit(newMessage("Broadcaster: Connect timeout for " + _mountpoint.toLatin1() + " (" + _outHost.toLatin1()+ ":" + QString("%1) ").arg(_outPort).toLatin1() + _outSocket->errorString().toLatin1(), true)); delete _outSocket; _outSocket = 0; return; } } else { _outSocket->connectToHostEncrypted(_outHost, _outPort); if (!_outSocket->waitForEncrypted(timeOut)) { emit(newMessage("Broadcaster: Connect timeout for " + _mountpoint.toLatin1() + " (" + _outHost.toLatin1()+ ":" + QString("%1) ").arg(_outPort).toLatin1() + _outSocket->errorString().toLatin1(), true)); delete _outSocket; _outSocket = 0; return; } } QByteArray msg; if (_ntripVersion == "1") { msg = "SOURCE " + _password.toLatin1() + " /" + _mountpoint.toLatin1() + "\r\n" + "Source-Agent: NTRIP BNC/" BNCVERSION "\r\n\r\n"; } else { msg = "POST " + _postExtension.toLatin1() + "/" + _mountpoint.toLatin1() + " HTTP/1.1\r\n" + "Host: " + _casterOutHost.toLatin1() + "\r\n" + "Ntrip-Version: Ntrip/2.0\r\n" + "Authorization: Basic " + (_userName + ":" + _password).toLatin1().toBase64() + "\r\n" + "User-Agent: NTRIP BNC/" BNCVERSION " (" + BNC_OS + ")\r\n" + "Connection: close\r\n" + "Transfer-Encoding: chunked\r\n\r\n"; } cout << msg.toStdString().c_str(); _outSocket->write(msg); _outSocket->waitForBytesWritten(); _outSocket->waitForReadyRead(); QByteArray ans = _outSocket->readLine();cout << ans.toStdString().c_str() << endl; if (ans.indexOf("OK") == -1) { delete _outSocket; _outSocket = 0; emit(newMessage("Broadcaster: Connection broken for " + _mountpoint.toLatin1() + ": " + ans.left(ans.length()-2), true)); } else { emit(newMessage("Broadcaster: Connection opened for " + _mountpoint.toLatin1() + ": " + ans.left(ans.length()-2), true)); _sOpenTrial = 0; } }