qlocalsocket_unix.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/network/socket/qlocalsocket_unix.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtNetwork module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39-
40#include "qlocalsocket.h"-
41#include "qlocalsocket_p.h"-
42#include "qnet_unix_p.h"-
43-
44#ifndef QT_NO_LOCALSOCKET-
45-
46#include <sys/types.h>-
47#include <sys/socket.h>-
48#include <sys/un.h>-
49#include <unistd.h>-
50#include <fcntl.h>-
51#include <errno.h>-
52-
53#include <qdir.h>-
54#include <qdebug.h>-
55#include <qelapsedtimer.h>-
56-
57#ifdef Q_OS_VXWORKS-
58# include <selectLib.h>-
59#endif-
60-
61#define QT_CONNECT_TIMEOUT 30000-
62-
63QT_BEGIN_NAMESPACE-
64-
65QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),-
66 delayConnect(0),-
67 connectTimer(0),-
68 connectingSocket(-1),-
69 connectingOpenMode(0),-
70 state(QLocalSocket::UnconnectedState)-
71{-
72}-
73-
74void QLocalSocketPrivate::init()-
75{-
76 Q_Q(QLocalSocket);-
77 // QIODevice signals-
78 q->connect(&unixSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));-
79 q->connect(&unixSocket, SIGNAL(bytesWritten(qint64)),-
80 q, SIGNAL(bytesWritten(qint64)));-
81 q->connect(&unixSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));-
82 // QAbstractSocket signals-
83 q->connect(&unixSocket, SIGNAL(connected()), q, SIGNAL(connected()));-
84 q->connect(&unixSocket, SIGNAL(disconnected()), q, SIGNAL(disconnected()));-
85 q->connect(&unixSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),-
86 q, SLOT(_q_stateChanged(QAbstractSocket::SocketState)));-
87 q->connect(&unixSocket, SIGNAL(error(QAbstractSocket::SocketError)),-
88 q, SLOT(_q_error(QAbstractSocket::SocketError)));-
89 q->connect(&unixSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));-
90 unixSocket.setParent(q);-
91}-
92-
93void QLocalSocketPrivate::_q_error(QAbstractSocket::SocketError socketError)-
94{-
95 Q_Q(QLocalSocket);-
96 QString function = QLatin1String("QLocalSocket");-
97 QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError;-
98 QString errorString = generateErrorString(error, function);-
99 q->setErrorString(errorString);-
100 emit q->error(error);-
101}-
102-
103void QLocalSocketPrivate::_q_stateChanged(QAbstractSocket::SocketState newState)-
104{-
105 Q_Q(QLocalSocket);-
106 QLocalSocket::LocalSocketState currentState = state;-
107 switch(newState) {-
108 case QAbstractSocket::UnconnectedState:-
109 state = QLocalSocket::UnconnectedState;-
110 serverName.clear();-
111 fullServerName.clear();-
112 break;-
113 case QAbstractSocket::ConnectingState:-
114 state = QLocalSocket::ConnectingState;-
115 break;-
116 case QAbstractSocket::ConnectedState:-
117 state = QLocalSocket::ConnectedState;-
118 break;-
119 case QAbstractSocket::ClosingState:-
120 state = QLocalSocket::ClosingState;-
121 break;-
122 default:-
123#if defined QLOCALSOCKET_DEBUG-
124 qWarning() << "QLocalSocket::Unhandled socket state change:" << newState;-
125#endif-
126 return;-
127 }-
128 if (currentState != state)-
129 emit q->stateChanged(state);-
130}-
131-
132QString QLocalSocketPrivate::generateErrorString(QLocalSocket::LocalSocketError error, const QString &function) const-
133{-
134 QString errorString;-
135 switch (error) {-
136 case QLocalSocket::ConnectionRefusedError:-
137 errorString = QLocalSocket::tr("%1: Connection refused").arg(function);-
138 break;-
139 case QLocalSocket::PeerClosedError:-
140 errorString = QLocalSocket::tr("%1: Remote closed").arg(function);-
141 break;-
142 case QLocalSocket::ServerNotFoundError:-
143 errorString = QLocalSocket::tr("%1: Invalid name").arg(function);-
144 break;-
145 case QLocalSocket::SocketAccessError:-
146 errorString = QLocalSocket::tr("%1: Socket access error").arg(function);-
147 break;-
148 case QLocalSocket::SocketResourceError:-
149 errorString = QLocalSocket::tr("%1: Socket resource error").arg(function);-
150 break;-
151 case QLocalSocket::SocketTimeoutError:-
152 errorString = QLocalSocket::tr("%1: Socket operation timed out").arg(function);-
153 break;-
154 case QLocalSocket::DatagramTooLargeError:-
155 errorString = QLocalSocket::tr("%1: Datagram too large").arg(function);-
156 break;-
157 case QLocalSocket::ConnectionError:-
158 errorString = QLocalSocket::tr("%1: Connection error").arg(function);-
159 break;-
160 case QLocalSocket::UnsupportedSocketOperationError:-
161 errorString = QLocalSocket::tr("%1: The socket operation is not supported").arg(function);-
162 break;-
163 case QLocalSocket::OperationError:-
164 errorString = QLocalSocket::tr("%1: Operation not permitted when socket is in this state").arg(function);-
165 break;-
166 case QLocalSocket::UnknownSocketError:-
167 default:-
168 errorString = QLocalSocket::tr("%1: Unknown error %2").arg(function).arg(errno);-
169 }-
170 return errorString;-
171}-
172-
173void QLocalSocketPrivate::errorOccurred(QLocalSocket::LocalSocketError error, const QString &function)-
174{-
175 Q_Q(QLocalSocket);-
176 switch (error) {-
177 case QLocalSocket::ConnectionRefusedError:-
178 unixSocket.setSocketError(QAbstractSocket::ConnectionRefusedError);-
179 break;-
180 case QLocalSocket::PeerClosedError:-
181 unixSocket.setSocketError(QAbstractSocket::RemoteHostClosedError);-
182 break;-
183 case QLocalSocket::ServerNotFoundError:-
184 unixSocket.setSocketError(QAbstractSocket::HostNotFoundError);-
185 break;-
186 case QLocalSocket::SocketAccessError:-
187 unixSocket.setSocketError(QAbstractSocket::SocketAccessError);-
188 break;-
189 case QLocalSocket::SocketResourceError:-
190 unixSocket.setSocketError(QAbstractSocket::SocketResourceError);-
191 break;-
192 case QLocalSocket::SocketTimeoutError:-
193 unixSocket.setSocketError(QAbstractSocket::SocketTimeoutError);-
194 break;-
195 case QLocalSocket::DatagramTooLargeError:-
196 unixSocket.setSocketError(QAbstractSocket::DatagramTooLargeError);-
197 break;-
198 case QLocalSocket::ConnectionError:-
199 unixSocket.setSocketError(QAbstractSocket::NetworkError);-
200 break;-
201 case QLocalSocket::UnsupportedSocketOperationError:-
202 unixSocket.setSocketError(QAbstractSocket::UnsupportedSocketOperationError);-
203 break;-
204 case QLocalSocket::UnknownSocketError:-
205 default:-
206 unixSocket.setSocketError(QAbstractSocket::UnknownSocketError);-
207 }-
208-
209 QString errorString = generateErrorString(error, function);-
210 q->setErrorString(errorString);-
211 emit q->error(error);-
212-
213 // errors cause a disconnect-
214 unixSocket.setSocketState(QAbstractSocket::UnconnectedState);-
215 bool stateChanged = (state != QLocalSocket::UnconnectedState);-
216 state = QLocalSocket::UnconnectedState;-
217 q->close();-
218 if (stateChanged)-
219 q->emit stateChanged(state);-
220}-
221-
222void QLocalSocket::connectToServer(OpenMode openMode)-
223{-
224 Q_D(QLocalSocket);-
225 if (state() == ConnectedState || state() == ConnectingState) {-
226 QString errorString = d->generateErrorString(QLocalSocket::OperationError, QLatin1String("QLocalSocket::connectToserver"));-
227 setErrorString(errorString);-
228 emit error(QLocalSocket::OperationError);-
229 return;-
230 }-
231-
232 d->errorString.clear();-
233 d->unixSocket.setSocketState(QAbstractSocket::ConnectingState);-
234 d->state = ConnectingState;-
235 emit stateChanged(d->state);-
236-
237 if (d->serverName.isEmpty()) {-
238 d->errorOccurred(ServerNotFoundError,-
239 QLatin1String("QLocalSocket::connectToServer"));-
240 return;-
241 }-
242-
243 // create the socket-
244 if (-1 == (d->connectingSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0, O_NONBLOCK))) {-
245 d->errorOccurred(UnsupportedSocketOperationError,-
246 QLatin1String("QLocalSocket::connectToServer"));-
247 return;-
248 }-
249-
250 // _q_connectToSocket does the actual connecting-
251 d->connectingName = d->serverName;-
252 d->connectingOpenMode = openMode;-
253 d->_q_connectToSocket();-
254 return;-
255}-
256-
257/*!-
258 \internal-
259-
260 Tries to connect connectingName and connectingOpenMode-
261-
262 \sa connectToServer(), waitForConnected()-
263 */-
264void QLocalSocketPrivate::_q_connectToSocket()-
265{-
266 Q_Q(QLocalSocket);-
267 QString connectingPathName;-
268-
269 // determine the full server path-
270 if (connectingName.startsWith(QLatin1Char('/'))) {-
271 connectingPathName = connectingName;-
272 } else {-
273 connectingPathName = QDir::tempPath();-
274 connectingPathName += QLatin1Char('/') + connectingName;-
275 }-
276-
277 const QByteArray encodedConnectingPathName = QFile::encodeName(connectingPathName);-
278 struct sockaddr_un name;-
279 name.sun_family = PF_UNIX;-
280 if (sizeof(name.sun_path) < (uint)encodedConnectingPathName.size() + 1) {-
281 QString function = QLatin1String("QLocalSocket::connectToServer");-
282 errorOccurred(QLocalSocket::ServerNotFoundError, function);-
283 return;-
284 }-
285 ::memcpy(name.sun_path, encodedConnectingPathName.constData(),-
286 encodedConnectingPathName.size() + 1);-
287 if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) {-
288 QString function = QLatin1String("QLocalSocket::connectToServer");-
289 switch (errno)-
290 {-
291 case EINVAL:-
292 case ECONNREFUSED:-
293 errorOccurred(QLocalSocket::ConnectionRefusedError, function);-
294 break;-
295 case ENOENT:-
296 errorOccurred(QLocalSocket::ServerNotFoundError, function);-
297 break;-
298 case EACCES:-
299 case EPERM:-
300 errorOccurred(QLocalSocket::SocketAccessError, function);-
301 break;-
302 case ETIMEDOUT:-
303 errorOccurred(QLocalSocket::SocketTimeoutError, function);-
304 break;-
305 case EAGAIN:-
306 // Try again later, all of the sockets listening are full-
307 if (!delayConnect) {-
308 delayConnect = new QSocketNotifier(connectingSocket, QSocketNotifier::Write, q);-
309 q->connect(delayConnect, SIGNAL(activated(int)), q, SLOT(_q_connectToSocket()));-
310 }-
311 if (!connectTimer) {-
312 connectTimer = new QTimer(q);-
313 q->connect(connectTimer, SIGNAL(timeout()),-
314 q, SLOT(_q_abortConnectionAttempt()),-
315 Qt::DirectConnection);-
316 connectTimer->start(QT_CONNECT_TIMEOUT);-
317 }-
318 delayConnect->setEnabled(true);-
319 break;-
320 default:-
321 errorOccurred(QLocalSocket::UnknownSocketError, function);-
322 }-
323 return;-
324 }-
325-
326 // connected!-
327 cancelDelayedConnect();-
328-
329 serverName = connectingName;-
330 fullServerName = connectingPathName;-
331 if (unixSocket.setSocketDescriptor(connectingSocket,-
332 QAbstractSocket::ConnectedState, connectingOpenMode)) {-
333 q->QIODevice::open(connectingOpenMode | QIODevice::Unbuffered);-
334 q->emit connected();-
335 } else {-
336 QString function = QLatin1String("QLocalSocket::connectToServer");-
337 errorOccurred(QLocalSocket::UnknownSocketError, function);-
338 }-
339 connectingSocket = -1;-
340 connectingName.clear();-
341 connectingOpenMode = 0;-
342}-
343-
344bool QLocalSocket::setSocketDescriptor(qintptr socketDescriptor,-
345 LocalSocketState socketState, OpenMode openMode)-
346{-
347 Q_D(QLocalSocket);-
348 QAbstractSocket::SocketState newSocketState = QAbstractSocket::UnconnectedState;-
349 switch (socketState) {-
350 case ConnectingState:-
351 newSocketState = QAbstractSocket::ConnectingState;-
352 break;-
353 case ConnectedState:-
354 newSocketState = QAbstractSocket::ConnectedState;-
355 break;-
356 case ClosingState:-
357 newSocketState = QAbstractSocket::ClosingState;-
358 break;-
359 case UnconnectedState:-
360 newSocketState = QAbstractSocket::UnconnectedState;-
361 break;-
362 }-
363 QIODevice::open(openMode);-
364 d->state = socketState;-
365 return d->unixSocket.setSocketDescriptor(socketDescriptor,-
366 newSocketState, openMode);-
367}-
368-
369void QLocalSocketPrivate::_q_abortConnectionAttempt()-
370{-
371 Q_Q(QLocalSocket);-
372 q->close();-
373}-
374-
375void QLocalSocketPrivate::cancelDelayedConnect()-
376{-
377 if (delayConnect) {-
378 delayConnect->setEnabled(false);-
379 delete delayConnect;-
380 delayConnect = 0;-
381 connectTimer->stop();-
382 delete connectTimer;-
383 connectTimer = 0;-
384 }-
385}-
386-
387qintptr QLocalSocket::socketDescriptor() const-
388{-
389 Q_D(const QLocalSocket);-
390 return d->unixSocket.socketDescriptor();-
391}-
392-
393qint64 QLocalSocket::readData(char *data, qint64 c)-
394{-
395 Q_D(QLocalSocket);-
396 return d->unixSocket.read(data, c);-
397}-
398-
399qint64 QLocalSocket::writeData(const char *data, qint64 c)-
400{-
401 Q_D(QLocalSocket);-
402 return d->unixSocket.writeData(data, c);-
403}-
404-
405void QLocalSocket::abort()-
406{-
407 Q_D(QLocalSocket);-
408 d->unixSocket.abort();-
409}-
410-
411qint64 QLocalSocket::bytesAvailable() const-
412{-
413 Q_D(const QLocalSocket);-
414 return QIODevice::bytesAvailable() + d->unixSocket.bytesAvailable();-
415}-
416-
417qint64 QLocalSocket::bytesToWrite() const-
418{-
419 Q_D(const QLocalSocket);-
420 return d->unixSocket.bytesToWrite();-
421}-
422-
423bool QLocalSocket::canReadLine() const-
424{-
425 Q_D(const QLocalSocket);-
426 return QIODevice::canReadLine() || d->unixSocket.canReadLine();-
427}-
428-
429void QLocalSocket::close()-
430{-
431 Q_D(QLocalSocket);-
432 d->unixSocket.close();-
433 d->cancelDelayedConnect();-
434 if (d->connectingSocket != -1)-
435 ::close(d->connectingSocket);-
436 d->connectingSocket = -1;-
437 d->connectingName.clear();-
438 d->connectingOpenMode = 0;-
439 d->serverName.clear();-
440 d->fullServerName.clear();-
441 QIODevice::close();-
442}-
443-
444bool QLocalSocket::waitForBytesWritten(int msecs)-
445{-
446 Q_D(QLocalSocket);-
447 return d->unixSocket.waitForBytesWritten(msecs);-
448}-
449-
450bool QLocalSocket::flush()-
451{-
452 Q_D(QLocalSocket);-
453 return d->unixSocket.flush();-
454}-
455-
456void QLocalSocket::disconnectFromServer()-
457{-
458 Q_D(QLocalSocket);-
459 d->unixSocket.disconnectFromHost();-
460}-
461-
462QLocalSocket::LocalSocketError QLocalSocket::error() const-
463{-
464 Q_D(const QLocalSocket);-
465 switch (d->unixSocket.error()) {-
466 case QAbstractSocket::ConnectionRefusedError:-
467 return QLocalSocket::ConnectionRefusedError;-
468 case QAbstractSocket::RemoteHostClosedError:-
469 return QLocalSocket::PeerClosedError;-
470 case QAbstractSocket::HostNotFoundError:-
471 return QLocalSocket::ServerNotFoundError;-
472 case QAbstractSocket::SocketAccessError:-
473 return QLocalSocket::SocketAccessError;-
474 case QAbstractSocket::SocketResourceError:-
475 return QLocalSocket::SocketResourceError;-
476 case QAbstractSocket::SocketTimeoutError:-
477 return QLocalSocket::SocketTimeoutError;-
478 case QAbstractSocket::DatagramTooLargeError:-
479 return QLocalSocket::DatagramTooLargeError;-
480 case QAbstractSocket::NetworkError:-
481 return QLocalSocket::ConnectionError;-
482 case QAbstractSocket::UnsupportedSocketOperationError:-
483 return QLocalSocket::UnsupportedSocketOperationError;-
484 case QAbstractSocket::UnknownSocketError:-
485 return QLocalSocket::UnknownSocketError;-
486 default:-
487#if defined QLOCALSOCKET_DEBUG-
488 qWarning() << "QLocalSocket error not handled:" << d->unixSocket.error();-
489#endif-
490 break;-
491 }-
492 return UnknownSocketError;-
493}-
494-
495bool QLocalSocket::isValid() const-
496{-
497 Q_D(const QLocalSocket);-
498 return d->unixSocket.isValid();-
499}-
500-
501qint64 QLocalSocket::readBufferSize() const-
502{-
503 Q_D(const QLocalSocket);-
504 return d->unixSocket.readBufferSize();-
505}-
506-
507void QLocalSocket::setReadBufferSize(qint64 size)-
508{-
509 Q_D(QLocalSocket);-
510 d->unixSocket.setReadBufferSize(size);-
511}-
512-
513bool QLocalSocket::waitForConnected(int msec)-
514{-
515 Q_D(QLocalSocket);-
516-
517 if (state() != ConnectingState)
state() != ConnectingStateDescription
TRUEevaluated 78 times by 2 tests
Evaluated by:
  • tst_QNetworkReply
  • tst_qlocalsocket - unknown status
FALSEnever evaluated
0-78
518 return (state() == ConnectedState);
executed 78 times by 2 tests: return (state() == ConnectedState);
Executed by:
  • tst_QNetworkReply
  • tst_qlocalsocket - unknown status
78
519-
520 fd_set fdsQElapsedTimer timer;-
521 FD_ZERO(&fds);-
FD_SETtimer.start();
522-
523 pollfd pfd = qt_make_pollfd(d->connectingSocket, &fdsPOLLIN);-
524-
525 timeval timeout;-
timeout.tv_sec = msec / 1000;do {
526 const int
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
timeout .tv_usec= (msec % 1000) * 1000;
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
0
if (
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
> 0== msec) timeout.tv_usec = 1000;
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
int result = -1;
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
QElapsedTimer timer;
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
timer.start();
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
while
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
? qMax(state() == ConnectingState
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
&& (-1 ==
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
msec ||- timer.elapsed() < msec(), Q_INT64_C(0)) {: msec;
(msec > 0)Description
TRUEnever evaluated
FALSEnever evaluated
527 const int result = ::selectqt_poll_msecs(d->connectingSocket + 1, &fds, 0&pfd, 01, &timeouttimeout);-
528-
529 if (-1 ==(result && errno != EINTR== -1)
result == -1Description
TRUEnever evaluated
FALSEnever evaluated
0
530 {d->errorOccurred(QLocalSocket::UnknownSocketError,
never executed: d->errorOccurred(QLocalSocket::UnknownSocketError, QLatin1String("QLocalSocket::waitForConnected"));
0
531 QLatin1String("QLocalSocket::waitForConnected"));
never executed: d->errorOccurred(QLocalSocket::UnknownSocketError, QLatin1String("QLocalSocket::waitForConnected"));
0
532 break;
result > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
}
result > 0Description
TRUEnever evaluated
FALSEnever evaluated
else if (result > 0)
result > 0Description
TRUEnever evaluated
FALSEnever evaluated
533 d->_q_connectToSocket();
never executed: d->_q_connectToSocket();
0
534 } while (state() == ConnectingState && !timer.hasExpired(msec));
never executed: end of block
state() == ConnectingStateDescription
TRUEnever evaluated
FALSEnever evaluated
!timer.hasExpired(msec)Description
TRUEnever evaluated
FALSEnever evaluated
0
535-
536 return (state() == ConnectedState);
never executed: return (state() == ConnectedState);
0
537}-
538-
539bool QLocalSocket::waitForDisconnected(int msecs)-
540{-
541 Q_D(QLocalSocket);-
542 if (state() == UnconnectedState) {-
543 qWarning("QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState");-
544 return false;-
545 }-
546 return (d->unixSocket.waitForDisconnected(msecs));-
547}-
548-
549bool QLocalSocket::waitForReadyRead(int msecs)-
550{-
551 Q_D(QLocalSocket);-
552 if (state() == QLocalSocket::UnconnectedState)-
553 return false;-
554 return (d->unixSocket.waitForReadyRead(msecs));-
555}-
556-
557QT_END_NAMESPACE-
558-
559#endif-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9