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

Last change on this file was 10227, checked in by stuerze, 6 months ago

minor changes

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