source: ntrip/trunk/BNC/src/upload/bncuploadcaster.cpp@ 10802

Last change on this file since 10802 was 10753, checked in by stuerze, 8 months ago

NtripSever functionallity added

File size: 12.5 KB
RevLine 
[3172]1/* -------------------------------------------------------------------------
2 * BKG NTRIP Server
3 * -------------------------------------------------------------------------
4 *
5 * Class: bncUploadCaster
6 *
7 * Purpose: Connection to NTRIP Caster
8 *
9 * Author: L. Mervart
10 *
11 * Created: 29-Mar-2011
12 *
[7661]13 * Changes:
[3172]14 *
15 * -----------------------------------------------------------------------*/
16
17#include <math.h>
[7661]18#include "bncuploadcaster.h"
[3172]19#include "bncversion.h"
[5070]20#include "bnccore.h"
[3235]21#include "bnctableitem.h"
[9707]22#include "bncsettings.h"
[9715]23#include "bncsslconfig.h"
[3172]24
25using namespace std;
26
27// Constructor
28////////////////////////////////////////////////////////////////////////////
[9715]29bncUploadCaster::bncUploadCaster(const QString &mountpoint,
30 const QString &outHost, int outPort, const QString &ntripVersion,
31 const QString &userName, const QString &password, int iRow, int rate) {
32 bncSettings settings;
33
34 _mountpoint = mountpoint;
[9707]35 _casterOutHost = outHost;
36 _casterOutPort = outPort;
[9715]37 _ntripVersion = ntripVersion;
38 _userName = userName;
39 _password = password;
40 _outSocket = 0;
41 _sOpenTrial = 0;
42 _iRow = iRow;
43 _rate = rate;
[9707]44
[9715]45 if (_rate < 0) {
[4809]46 _rate = 0;
[9715]47 } else if (_rate > 60) {
[3273]48 _rate = 60;
49 }
[3207]50 _isToBeDeleted = false;
[3235]51
[9732]52 connect(this, SIGNAL(newMessage(QByteArray,bool)), BNC_CORE, SLOT(slotMessage(const QByteArray,bool)));
[3235]53
[9732]54 if (BNC_CORE->_uploadTableItems.find(_iRow) != BNC_CORE->_uploadTableItems.end()) {
[7661]55 connect(this, SIGNAL(newBytes(QByteArray,double)),
[9732]56 BNC_CORE->_uploadTableItems.value(iRow),
57 SLOT(slotNewBytes(const QByteArray,double)));
[3235]58 }
[10753]59
[9732]60 if (BNC_CORE->_uploadEphTableItems.find(_iRow) != BNC_CORE->_uploadEphTableItems.end()) {
[8733]61 connect(this, SIGNAL(newBytes(QByteArray,double)),
[9732]62 BNC_CORE->_uploadEphTableItems.value(iRow),
63 SLOT(slotNewBytes(const QByteArray,double)));
[8733]64 }
[9714]65
[10753]66 if (BNC_CORE->_uploadRawTableItems.find(_iRow) != BNC_CORE->_uploadRawTableItems.end()) {
67 connect(this, SIGNAL(newBytes(QByteArray,double)),
68 BNC_CORE->_uploadRawTableItems.value(iRow),
69 SLOT(slotNewBytes(const QByteArray,double)));
70 }
71
72
[9732]73 _sslIgnoreErrors = (Qt::CheckState(settings.value("sslIgnoreErrors").toInt()) == Qt::Checked);
[9714]74
[9715]75 _proxyOutHost = settings.value("proxyHost").toString();
76 _proxyOutPort = settings.value("proxyPort").toInt();
77 (_proxyOutHost.isEmpty()) ? _proxy = false : _proxy = true;
78
79 _secure = false;
[9714]80 if (_ntripVersion == "2s") {
81 if (!QSslSocket::supportsSsl()) {
[9715]82 emit(newMessage(
83 "For SSL support please install OpenSSL run-time libraries: Ntrip Version 2 is tried",
84 true));
[9714]85 _ntripVersion == "2";
[9715]86 } else {
87 _secure = true;
88 _casterOutPort = 443;
[9795]89 // Generate filenames to consider a potential client certificate and private key
90 _crtFileName = settings.value("sslClientCertPath").toString() + _casterOutHost + QString(".%1.crt").arg(_casterOutPort);
91 _keyFileName = settings.value("sslClientCertPath").toString() + _casterOutHost + QString(".%1.key").arg(_casterOutPort);
[9714]92 }
93 }
94
[9715]95 if (!_secure && _proxy) {
96 _postExtension = QString("http://%1:%2").arg(_casterOutHost).arg(_casterOutPort);
97 } else {
98 _postExtension = "";
[9714]99 }
[3172]100}
101
[3207]102// Safe Desctructor
103////////////////////////////////////////////////////////////////////////////
104void bncUploadCaster::deleteSafely() {
105 _isToBeDeleted = true;
[3208]106 if (!isRunning()) {
107 delete this;
108 }
[3207]109}
110
[3172]111// Destructor
112////////////////////////////////////////////////////////////////////////////
113bncUploadCaster::~bncUploadCaster() {
[3208]114 if (isRunning()) {
115 wait();
116 }
[7661]117 if (_outSocket) {
118 delete _outSocket;
119 }
[3172]120}
121
[9707]122//
123////////////////////////////////////////////////////////////////////////////
124void bncUploadCaster::slotProxyAuthenticationRequired(const QNetworkProxy&,
[9715]125 QAuthenticator*) {
[9707]126 emit newMessage("slotProxyAuthenticationRequired", true);
127}
128
[9726]129// TSL/SSL
130 ////////////////////////////////////////////////////////////////////////////
131void bncUploadCaster::slotSslErrors(QList<QSslError> errors) {
132 QString msg = "SSL Error: ";
133 if (_outSocket) {
134 QSslCertificate cert = _outSocket->sslConfiguration().peerCertificate();
135 if (!cert.isNull() &&
136 cert.issuerInfo(QSslCertificate::OrganizationalUnitName).count() &&
137 cert.issuerInfo(QSslCertificate::Organization).count()) {
[9736]138 msg += QString("Server Certificate Issued by:\n" "%1\n%2\nCannot be verified\n")
[9726]139#if QT_VERSION >= 0x050000
140 .arg(cert.issuerInfo(QSslCertificate::OrganizationalUnitName).at(0))
141 .arg(cert.issuerInfo(QSslCertificate::Organization).at(0));
142#else
143 .arg(cert.issuerInfo(QSslCertificate::OrganizationalUnitName))
144 .arg(cert.issuerInfo(QSslCertificate::Organization));
145#endif
146 }
147
148 QListIterator<QSslError> it(errors);
149 while (it.hasNext()) {
150 const QSslError& err = it.next();
151 msg += err.errorString();
152 }
[9740]153 emit(newMessage(msg.toLatin1(), true));
[9726]154 }
155}
156
157
[3226]158// Endless Loop
159////////////////////////////////////////////////////////////////////////////
160void bncUploadCaster::run() {
161 while (true) {
162 if (_isToBeDeleted) {
163 QThread::quit();
164 deleteLater();
165 return;
166 }
167 open();
168 if (_outSocket && _outSocket->state() == QAbstractSocket::ConnectedState) {
169 QMutexLocker locker(&_mutex);
[4808]170 if (_outBuffer.size() > 0) {
[9707]171 if (_ntripVersion == "1") {
172 _outSocket->write(_outBuffer);
[10227]173 _outSocket->flush();
[9715]174 } else {
[9732]175 QString chunkSize = QString("%1").arg(_outBuffer.size(), 0, 16, QLatin1Char('0'));
176 QByteArray chunkedData = chunkSize.toLatin1() + "\r\n" + _outBuffer + "\r\n";
[9707]177 _outSocket->write(chunkedData);
[10227]178 _outSocket->flush();
[9707]179 }
[8204]180 emit newBytes(_mountpoint.toLatin1(), _outBuffer.size());
[4808]181 }
[3226]182 }
[4809]183 if (_rate == 0) {
[4985]184 {
185 QMutexLocker locker(&_mutex);
186 _outBuffer.clear();
187 }
[8708]188 msleep(100); //sleep 0.1 sec
[9715]189 } else {
[4809]190 sleep(_rate);
191 }
[3226]192 }
193}
194
[3172]195// Start the Communication with NTRIP Caster
196////////////////////////////////////////////////////////////////////////////
197void bncUploadCaster::open() {
[9715]198 const int timeOut = 5000; // 5 seconds
199 QByteArray msg;
[3172]200
201 if (_mountpoint.isEmpty()) {
202 return;
203 }
204
[9748]205 if (_outSocket != 0 &&
206 _outSocket->state() == QAbstractSocket::ConnectedState) {
207 return;
[3172]208 }
[9712]209
[9748]210 delete _outSocket; _outSocket = 0;
211
[9715]212 double minDt = pow(2.0, _sOpenTrial);
[3172]213 if (++_sOpenTrial > 4) {
214 _sOpenTrial = 4;
215 }
[9715]216 if (_outSocketOpenTime.isValid()
217 && _outSocketOpenTime.secsTo(QDateTime::currentDateTime()) < minDt) {
[3172]218 return;
[9715]219 } else {
[3172]220 _outSocketOpenTime = QDateTime::currentDateTime();
221 }
222
[9707]223 _outSocket = new QSslSocket();
[9728]224 _outSocket->setProxy(QNetworkProxy::NoProxy);
[9741]225
226 if (_sslIgnoreErrors) {
227 _outSocket->ignoreSslErrors();
228 } else {
[9795]229 bncSslConfig sslConfig = BNC_SSL_CONFIG;
230 QFile clientCrtFile(_crtFileName);
231 QFile privateKeyFile(_keyFileName);
232 if ( clientCrtFile.exists() && privateKeyFile.exists()) {
233 // set local certificate
234 clientCrtFile.open(QIODevice::ReadOnly);
235 QSslCertificate clientCrt(&clientCrtFile);
236 sslConfig.setLocalCertificate(clientCrt);
237 // set private key if available
238 privateKeyFile.open(QIODevice::ReadOnly);
239 QSslKey privateKey(&privateKeyFile, QSsl::Rsa);
240 sslConfig.setPrivateKey(privateKey);
241 }
242 _outSocket->setSslConfiguration(sslConfig);
[9741]243 connect(_outSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
244 }
245
[9730]246 if (!_proxy) {
247 if (!connectToHost(_casterOutHost, _casterOutPort, _secure)) {
248 return;
249 }
250 } else {
[9715]251 if (_ntripVersion == "1") {
252 emit(newMessage("No proxy support in Ntrip Version 1 upload!", true));
[9748]253 delete _outSocket; _outSocket = 0;
[9713]254 return;
255 }
[9715]256 connect(_outSocket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
257 this,SLOT(slotProxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)));
258
259 if (!connectToHost(_proxyOutHost, _proxyOutPort, false)) {
260 return;
261 }
262
263 if (_secure) {
264 msg = "CONNECT " + _casterOutHost.toLatin1() + ":"
265 + QString("%1").arg(_casterOutPort).toLatin1() + " HTTP/1.1\r\n"
266 + "Proxy-Connection: Keep-Alive\r\n"
267 + "Host: " + _casterOutHost.toLatin1() + "\r\n"
268 + "User-Agent: NTRIP BNC/" BNCVERSION " (" + BNC_OS + ")\r\n"
[9743]269 + "\r\n";
[9715]270 _outSocket->write(msg);
271 _outSocket->waitForBytesWritten();
272 _outSocket->waitForReadyRead();
[9737]273
[9743]274 QByteArray ans = _outSocket->readAll();
[9715]275 if (ans.indexOf("200") == -1) {
[9743]276 int l = ans.indexOf("\r\n", 0);
[9851]277 emit(newMessage("Proxy: Connection broken for " + _mountpoint.toLatin1() + "@" +
278 _casterOutHost.toLatin1() + ":" + QString("%1").arg(_casterOutPort).toLatin1() + ": " + ans.left(l), true));
[9748]279 delete _outSocket; _outSocket = 0;
[9715]280 return;
281 } else {
[9853]282 emit(newMessage("Proxy: Connection established for " + _mountpoint.toLatin1()+ "@" +
283 _casterOutHost.toLatin1() + ":" + QString("%1").arg(_casterOutPort).toLatin1() , true));
[9715]284 _sOpenTrial = 0;
285 _outSocket->setPeerVerifyName(_casterOutHost);
286 _outSocket->startClientEncryption();
287 if (!_outSocket->waitForEncrypted(timeOut)) {
[9851]288 emit(newMessage("Proxy/Caster: Encrypt timeout for " + _mountpoint.toLatin1() + "@"
[9732]289 + _casterOutHost.toLatin1() + ":"
290 + QString("%1) ").arg(_casterOutPort).toLatin1()
291 + _outSocket->errorString().toLatin1(), true));
[9748]292 delete _outSocket; _outSocket = 0;
[9715]293 return;
294 } else {
[9851]295 emit(newMessage("Proxy: SSL handshake completed for " + _mountpoint.toLatin1() + "@" +
296 _casterOutHost.toLatin1() + ":" + QString("%1").arg(_casterOutPort).toLatin1(), true));
[9715]297 }
298 }
299 }
[9707]300 }
301
302 if (_ntripVersion == "1") {
[9715]303 msg = "SOURCE " + _password.toLatin1() + " /" + _mountpoint.toLatin1()
304 + "\r\n" + "Source-Agent: NTRIP BNC/" BNCVERSION "\r\n\r\n";
[10221]305 _outSocket->write(msg);
306 _outSocket->waitForBytesWritten();
307 _outSocket->waitForReadyRead();
[9715]308 } else {
309 msg = "POST " + _postExtension.toLatin1() + "/" + _mountpoint.toLatin1()
310 + " HTTP/1.1\r\n" + "Host: " + _casterOutHost.toLatin1() + "\r\n"
311 + "Ntrip-Version: Ntrip/2.0\r\n" + "Authorization: Basic "
312 + (_userName + ":" + _password).toLatin1().toBase64() + "\r\n"
313 + "User-Agent: NTRIP BNC/" BNCVERSION " (" + BNC_OS + ")\r\n"
314 + "Connection: close\r\n" + "Transfer-Encoding: chunked\r\n\r\n";
[10221]315 _outSocket->write(msg);
316 _outSocket->waitForBytesWritten();
317 _outSocket->waitForReadyRead();
[9707]318 }
[3172]319
[9743]320 QByteArray ans = _outSocket->readAll();
[9715]321
322 if (ans.indexOf("200") == -1) {
[9748]323 delete _outSocket; _outSocket = 0;
[9743]324 int l = ans.indexOf("\r\n", 0);
[9853]325 emit(newMessage("Broadcaster: Connection broken for " + _mountpoint.toLatin1() + "@" +
[9851]326 _casterOutHost.toLatin1() + ":" + QString("%1").arg(_casterOutPort).toLatin1() +
327 ": " + ans.left(l), true));
[9715]328 } else {
[9851]329 emit(newMessage("Broadcaster: Connection opened for " + _mountpoint.toLatin1() + "@" +
330 _casterOutHost.toLatin1() + ":" + QString("%1").arg(_casterOutPort).toLatin1() , true));
[3172]331 _sOpenTrial = 0;
332 }
333}
334
[9715]335// Try connection to NTRIP Caster or Proxy
336////////////////////////////////////////////////////////////////////////////
337bool bncUploadCaster::connectToHost(QString outHost, int outPort, bool encrypted) {
338 const int timeOut = 5000; // 5 seconds
339 if (encrypted) {
340 _outSocket->connectToHostEncrypted(outHost, outPort);
341 if (!_outSocket->waitForEncrypted(timeOut)) {
342 emit(newMessage(
[9851]343 "Broadcaster: Connect timeout for " + _mountpoint.toLatin1() + "@"
[9715]344 + outHost.toLatin1() + ":"
345 + QString("%1) ").arg(outPort).toLatin1()
346 + _outSocket->errorString().toLatin1(), true));
[9748]347 delete _outSocket; _outSocket = 0;
[9715]348 return false;
[9717]349 } else {
[9851]350 emit(newMessage("Broadcaster: SSL handshake completed for " + _mountpoint.toLatin1() + "@" +
351 _casterOutHost.toLatin1() + ":" + QString("%1").arg(_casterOutPort).toLatin1(), true));
[9715]352 }
353 } else {
354 _outSocket->connectToHost(outHost, outPort);
355 if (!_outSocket->waitForConnected(timeOut)) {
[9851]356 emit(newMessage("Broadcaster: Connect timeout for " + _mountpoint.toLatin1() + "@"
[9715]357 + outHost.toLatin1() + ":"
358 + QString("%1) ").arg(outPort).toLatin1()
359 + _outSocket->errorString().toLatin1(), true));
[9748]360 delete _outSocket; _outSocket = 0;
[9715]361 return false;
362 }
363 }
364 return true;
365}
366
367
Note: See TracBrowser for help on using the repository browser.