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

Last change on this file since 9739 was 9739, checked in by stuerze, 2 months ago

minor changes

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