10#include <sys/socket.h>
17#include <qdeadlinetimer.h>
19#include <qstringconverter.h>
22# include <selectLib.h>
25using namespace std::chrono_literals;
27#define QT_CONNECT_TIMEOUT 30000
31using namespace Qt::StringLiterals;
35static QString pathNameForConnection(
const QString &connectingName,
36 QLocalSocket::SocketOptions options)
38 if (options.testFlag(QLocalSocket::AbstractNamespaceOption)
39 || connectingName.startsWith(u'/')) {
40 return connectingName;
43 return QDir::tempPath() + u'/' + connectingName;
46static QLocalSocket::SocketOptions optionsForPlatform(QLocalSocket::SocketOptions srcOptions)
50 if (!PlatformSupportsAbstractNamespace)
51 return QLocalSocket::NoOptions;
57 delayConnect(
nullptr),
58 connectTimer(
nullptr),
60 state(QLocalSocket::UnconnectedState),
61 socketOptions(QLocalSocket::NoOptions)
69 q->connect(&unixSocket, SIGNAL(bytesWritten(qint64)),
70 q, SIGNAL(bytesWritten(qint64)));
71 q->connect(&unixSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
73 q->connect(&unixSocket, SIGNAL(connected()), q, SIGNAL(connected()));
74 q->connect(&unixSocket, SIGNAL(disconnected()), q, SIGNAL(disconnected()));
75 q->connect(&unixSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
76 q, SLOT(_q_stateChanged(QAbstractSocket::SocketState)));
77 q->connect(&unixSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
78 q, SLOT(_q_errorOccurred(QAbstractSocket::SocketError)));
79 q->connect(&unixSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));
80 unixSocket.setParent(q);
86 QString function =
"QLocalSocket"_L1;
87 QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError;
88 QString errorString = generateErrorString(error, function);
89 q->setErrorString(errorString);
90 emit q->errorOccurred(error);
96 QLocalSocket::LocalSocketState currentState = state;
98 case QAbstractSocket::UnconnectedState:
99 state = QLocalSocket::UnconnectedState;
101 fullServerName.clear();
103 case QAbstractSocket::ConnectingState:
104 state = QLocalSocket::ConnectingState;
106 case QAbstractSocket::ConnectedState:
107 state = QLocalSocket::ConnectedState;
109 case QAbstractSocket::ClosingState:
110 state = QLocalSocket::ClosingState;
113#if defined QLOCALSOCKET_DEBUG
114 qWarning() <<
"QLocalSocket::Unhandled socket state change:" << newState;
118 if (currentState != state)
119 emit q->stateChanged(state);
126 case QLocalSocket::ConnectionRefusedError:
127 errorString = QLocalSocket::tr(
"%1: Connection refused").arg(function);
129 case QLocalSocket::PeerClosedError:
130 errorString = QLocalSocket::tr(
"%1: Remote closed").arg(function);
132 case QLocalSocket::ServerNotFoundError:
133 errorString = QLocalSocket::tr(
"%1: Invalid name").arg(function);
135 case QLocalSocket::SocketAccessError:
136 errorString = QLocalSocket::tr(
"%1: Socket access error").arg(function);
138 case QLocalSocket::SocketResourceError:
139 errorString = QLocalSocket::tr(
"%1: Socket resource error").arg(function);
141 case QLocalSocket::SocketTimeoutError:
142 errorString = QLocalSocket::tr(
"%1: Socket operation timed out").arg(function);
144 case QLocalSocket::DatagramTooLargeError:
145 errorString = QLocalSocket::tr(
"%1: Datagram too large").arg(function);
147 case QLocalSocket::ConnectionError:
148 errorString = QLocalSocket::tr(
"%1: Connection error").arg(function);
150 case QLocalSocket::UnsupportedSocketOperationError:
151 errorString = QLocalSocket::tr(
"%1: The socket operation is not supported").arg(function);
153 case QLocalSocket::OperationError:
154 errorString = QLocalSocket::tr(
"%1: Operation not permitted when socket is in this state").arg(function);
156 case QLocalSocket::UnknownSocketError:
158 errorString = QLocalSocket::tr(
"%1: Unknown error %2").arg(function).arg(errno);
167 case QLocalSocket::ConnectionRefusedError:
168 unixSocket.setSocketError(QAbstractSocket::ConnectionRefusedError);
170 case QLocalSocket::PeerClosedError:
171 unixSocket.setSocketError(QAbstractSocket::RemoteHostClosedError);
173 case QLocalSocket::ServerNotFoundError:
174 unixSocket.setSocketError(QAbstractSocket::HostNotFoundError);
176 case QLocalSocket::SocketAccessError:
177 unixSocket.setSocketError(QAbstractSocket::SocketAccessError);
179 case QLocalSocket::SocketResourceError:
180 unixSocket.setSocketError(QAbstractSocket::SocketResourceError);
182 case QLocalSocket::SocketTimeoutError:
183 unixSocket.setSocketError(QAbstractSocket::SocketTimeoutError);
185 case QLocalSocket::DatagramTooLargeError:
186 unixSocket.setSocketError(QAbstractSocket::DatagramTooLargeError);
188 case QLocalSocket::ConnectionError:
189 unixSocket.setSocketError(QAbstractSocket::NetworkError);
191 case QLocalSocket::UnsupportedSocketOperationError:
192 unixSocket.setSocketError(QAbstractSocket::UnsupportedSocketOperationError);
194 case QLocalSocket::UnknownSocketError:
196 unixSocket.setSocketError(QAbstractSocket::UnknownSocketError);
199 QString errorString = generateErrorString(error, function);
200 q->setErrorString(errorString);
201 emit q->errorOccurred(error);
204 unixSocket.setSocketState(QAbstractSocket::UnconnectedState);
205 bool stateChanged = (state != QLocalSocket::UnconnectedState);
206 state = QLocalSocket::UnconnectedState;
209 q->emit stateChanged(state);
212void QLocalSocket::connectToServer(OpenMode openMode)
215 if (state() == ConnectedState || state() == ConnectingState) {
216 QString errorString = d->generateErrorString(QLocalSocket::OperationError,
"QLocalSocket::connectToserver"_L1);
217 setErrorString(errorString);
218 emit errorOccurred(QLocalSocket::OperationError);
222 d->errorString.clear();
223 d->unixSocket.setSocketState(QAbstractSocket::ConnectingState);
224 d->state = ConnectingState;
225 emit stateChanged(d->state);
227 if (d->serverName.isEmpty()) {
228 d->setErrorAndEmit(ServerNotFoundError,
"QLocalSocket::connectToServer"_L1);
233 if (-1 == (d->connectingSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0, O_NONBLOCK))) {
234 d->setErrorAndEmit(UnsupportedSocketOperationError,
"QLocalSocket::connectToServer"_L1);
239 d->connectingName = d->serverName;
240 d->connectingOpenMode = openMode;
241 d->_q_connectToSocket();
246
247
248
249
250
251
256 QLocalSocket::SocketOptions options = optionsForPlatform(socketOptions);
257 const QString connectingPathName = pathNameForConnection(connectingName, options);
258 const QByteArray encodedConnectingPathName = QFile::encodeName(connectingPathName);
259 struct ::sockaddr_un addr;
260 addr.sun_family = PF_UNIX;
261 memset(addr.sun_path, 0,
sizeof(addr.sun_path));
264 constexpr unsigned int extraCharacters = PlatformSupportsAbstractNamespace ? 2 : 1;
266 if (
sizeof(addr.sun_path) <
static_cast<size_t>(encodedConnectingPathName.size() + extraCharacters)) {
267 QString function =
"QLocalSocket::connectToServer"_L1;
268 setErrorAndEmit(QLocalSocket::ServerNotFoundError, function);
272 QT_SOCKLEN_T addrSize =
sizeof(::sockaddr_un);
273 if (options.testFlag(QLocalSocket::AbstractNamespaceOption)) {
274 ::memcpy(addr.sun_path + 1, encodedConnectingPathName.constData(),
275 encodedConnectingPathName.size() + 1);
276 addrSize = offsetof(::sockaddr_un, sun_path) + encodedConnectingPathName.size() + 1;
278 ::memcpy(addr.sun_path, encodedConnectingPathName.constData(),
279 encodedConnectingPathName.size() + 1);
281 if (-1 == qt_safe_connect(connectingSocket, (
struct sockaddr *)&addr, addrSize)) {
282 QString function =
"QLocalSocket::connectToServer"_L1;
287 setErrorAndEmit(QLocalSocket::ConnectionRefusedError, function);
290 setErrorAndEmit(QLocalSocket::ServerNotFoundError, function);
294 setErrorAndEmit(QLocalSocket::SocketAccessError, function);
297 setErrorAndEmit(QLocalSocket::SocketTimeoutError, function);
302 delayConnect =
new QSocketNotifier(connectingSocket, QSocketNotifier::Write, q);
303 q->connect(delayConnect, SIGNAL(activated(QSocketDescriptor)), q, SLOT(_q_connectToSocket()));
306 connectTimer =
new QTimer(q);
307 q->connect(connectTimer, SIGNAL(timeout()),
308 q, SLOT(_q_abortConnectionAttempt()),
309 Qt::DirectConnection);
312 delayConnect->setEnabled(
true);
315 setErrorAndEmit(QLocalSocket::UnknownSocketError, function);
323 serverName = connectingName;
324 fullServerName = connectingPathName;
325 if (unixSocket.setSocketDescriptor(connectingSocket,
326 QAbstractSocket::ConnectedState, connectingOpenMode)) {
327 q->QIODevice::open(connectingOpenMode);
330 QString function =
"QLocalSocket::connectToServer"_L1;
331 setErrorAndEmit(QLocalSocket::UnknownSocketError, function);
334 connectingName.clear();
335 connectingOpenMode = { };
338bool QLocalSocket::setSocketDescriptor(qintptr socketDescriptor,
339 LocalSocketState socketState, OpenMode openMode)
342 QAbstractSocket::SocketState newSocketState = QAbstractSocket::UnconnectedState;
343 switch (socketState) {
344 case ConnectingState:
345 newSocketState = QAbstractSocket::ConnectingState;
348 newSocketState = QAbstractSocket::ConnectedState;
351 newSocketState = QAbstractSocket::ClosingState;
353 case UnconnectedState:
354 newSocketState = QAbstractSocket::UnconnectedState;
357 QIODevice::open(openMode);
358 d->state = socketState;
359 d->describeSocket(socketDescriptor);
360 const bool result = d->unixSocket.setSocketDescriptor(socketDescriptor,
361 newSocketState, openMode);
366 emit stateChanged(d->state);
372 bool abstractAddress =
false;
374 struct ::sockaddr_un addr;
375 QT_SOCKLEN_T len =
sizeof(addr);
376 memset(&addr, 0,
sizeof(addr));
377 const int getpeernameStatus = ::getpeername(socketDescriptor, (sockaddr *)&addr, &len);
378 if (getpeernameStatus != 0 || len == offsetof(sockaddr_un, sun_path)) {
381 if (::getsockname(socketDescriptor, (sockaddr *)&addr, &len) != 0)
384 if (parseSockaddr(addr,
static_cast<uint>(len), fullServerName, serverName, abstractAddress)) {
385 QLocalSocket::SocketOptions options = socketOptions.value();
386 socketOptions = options.setFlag(QLocalSocket::AbstractNamespaceOption, abstractAddress);
392 QString &fullServerName,
394 bool &abstractNamespace)
396 if (len <= offsetof(::sockaddr_un, sun_path))
398 len -= offsetof(::sockaddr_un, sun_path);
400 abstractNamespace = PlatformSupportsAbstractNamespace
401 && (addr.sun_family == PF_UNIX && addr.sun_path[0] == 0);
402 QStringDecoder toUtf16(QStringDecoder::System, QStringDecoder::Flag::Stateless);
406 QByteArrayView textData(addr.sun_path + (abstractNamespace ? 1 : 0),
407 len - (abstractNamespace ? 1 : 0));
408 QString name = toUtf16(textData);
409 if (!name.isEmpty() && !toUtf16.hasError()) {
412 if (!abstractNamespace && (name.at(name.size() - 1) == QChar::fromLatin1(
'\0'))) {
413 int truncPos = name.size() - 1;
414 while (truncPos > 0 && name.at(truncPos - 1) == QChar::fromLatin1(
'\0'))
416 name.truncate(truncPos);
418 fullServerName = name;
419 serverName = abstractNamespace
421 : fullServerName.mid(fullServerName.lastIndexOf(u'/') + 1);
422 if (serverName.isEmpty())
423 serverName = fullServerName;
437 delayConnect->setEnabled(
false);
439 delayConnect =
nullptr;
440 connectTimer->stop();
442 connectTimer =
nullptr;
446qintptr QLocalSocket::socketDescriptor()
const
448 Q_D(
const QLocalSocket);
449 return d->unixSocket.socketDescriptor();
452qint64 QLocalSocket::readData(
char *data, qint64 c)
455 return d->unixSocket.read(data, c);
458qint64 QLocalSocket::readLineData(
char *data, qint64 maxSize)
465 return d_func()->unixSocket.readLine(data, maxSize + 1);
468qint64 QLocalSocket::skipData(qint64 maxSize)
470 return d_func()->unixSocket.skip(maxSize);
473qint64 QLocalSocket::writeData(
const char *data, qint64 c)
476 return d->unixSocket.writeData(data, c);
479void QLocalSocket::abort()
482 d->unixSocket.abort();
486qint64 QLocalSocket::bytesAvailable()
const
488 Q_D(
const QLocalSocket);
489 return QIODevice::bytesAvailable() + d->unixSocket.bytesAvailable();
492qint64 QLocalSocket::bytesToWrite()
const
494 Q_D(
const QLocalSocket);
495 return d->unixSocket.bytesToWrite();
498bool QLocalSocket::canReadLine()
const
500 Q_D(
const QLocalSocket);
501 return QIODevice::canReadLine() || d->unixSocket.canReadLine();
504void QLocalSocket::close()
509 d->unixSocket.close();
510 d->cancelDelayedConnect();
511 if (d->connectingSocket != -1)
512 ::close(d->connectingSocket);
513 d->connectingSocket = -1;
514 d->connectingName.clear();
515 d->connectingOpenMode = { };
516 d->serverName.clear();
517 d->fullServerName.clear();
520bool QLocalSocket::waitForBytesWritten(
int msecs)
523 return d->unixSocket.waitForBytesWritten(msecs);
526bool QLocalSocket::flush()
529 return d->unixSocket.flush();
532void QLocalSocket::disconnectFromServer()
535 d->unixSocket.disconnectFromHost();
538QLocalSocket::LocalSocketError QLocalSocket::error()
const
540 Q_D(
const QLocalSocket);
541 switch (d->unixSocket.error()) {
542 case QAbstractSocket::ConnectionRefusedError:
543 return QLocalSocket::ConnectionRefusedError;
544 case QAbstractSocket::RemoteHostClosedError:
545 return QLocalSocket::PeerClosedError;
546 case QAbstractSocket::HostNotFoundError:
547 return QLocalSocket::ServerNotFoundError;
548 case QAbstractSocket::SocketAccessError:
549 return QLocalSocket::SocketAccessError;
550 case QAbstractSocket::SocketResourceError:
551 return QLocalSocket::SocketResourceError;
552 case QAbstractSocket::SocketTimeoutError:
553 return QLocalSocket::SocketTimeoutError;
554 case QAbstractSocket::DatagramTooLargeError:
555 return QLocalSocket::DatagramTooLargeError;
556 case QAbstractSocket::NetworkError:
557 return QLocalSocket::ConnectionError;
558 case QAbstractSocket::UnsupportedSocketOperationError:
559 return QLocalSocket::UnsupportedSocketOperationError;
560 case QAbstractSocket::UnknownSocketError:
561 return QLocalSocket::UnknownSocketError;
563#if defined QLOCALSOCKET_DEBUG
564 qWarning() <<
"QLocalSocket error not handled:" << d->unixSocket.error();
568 return UnknownSocketError;
571bool QLocalSocket::isValid()
const
573 Q_D(
const QLocalSocket);
574 return d->unixSocket.isValid();
577qint64 QLocalSocket::readBufferSize()
const
579 Q_D(
const QLocalSocket);
580 return d->unixSocket.readBufferSize();
583void QLocalSocket::setReadBufferSize(qint64 size)
586 d->unixSocket.setReadBufferSize(size);
589bool QLocalSocket::waitForConnected(
int msec)
593 if (state() != ConnectingState)
594 return (state() == ConnectedState);
596 pollfd pfd = qt_make_pollfd(d->connectingSocket, POLLIN);
598 QDeadlineTimer deadline{msec};
599 auto remainingTime = deadline.remainingTimeAsDuration();
602 const int result = qt_safe_poll(&pfd, 1, deadline);
604 d->setErrorAndEmit(QLocalSocket::UnknownSocketError,
605 "QLocalSocket::waitForConnected"_L1);
607 d->_q_connectToSocket();
608 }
while (state() == ConnectingState
609 && (remainingTime = deadline.remainingTimeAsDuration()) > 0ns);
611 return (state() == ConnectedState);
614bool QLocalSocket::waitForDisconnected(
int msecs)
617 if (state() == UnconnectedState) {
618 qWarning(
"QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState");
621 return (d->unixSocket.waitForDisconnected(msecs));
624bool QLocalSocket::waitForReadyRead(
int msecs)
627 if (state() == QLocalSocket::UnconnectedState)
629 return (d->unixSocket.waitForReadyRead(msecs));
void _q_stateChanged(QAbstractSocket::SocketState newState)
void describeSocket(qintptr socketDescriptor)
void _q_abortConnectionAttempt()
void cancelDelayedConnect()
void _q_errorOccurred(QAbstractSocket::SocketError newError)
void setErrorAndEmit(QLocalSocket::LocalSocketError, const QString &function)
void _q_connectToSocket()
QString generateErrorString(QLocalSocket::LocalSocketError, const QString &function) const
#define QT_CONNECT_TIMEOUT