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

Last change on this file since 9731 was 9731, checked in by stuerze, 2 years ago

minor changes

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