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

Last change on this file since 9735 was 9735, checked in by stuerze, 23 months ago

minor changes

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