/src/qtbase/src/network/socket/qlocalsocket_unix.cpp
Line | Count | Source |
1 | | // Copyright (C) 2016 The Qt Company Ltd. |
2 | | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | | // Qt-Security score:significant reason:default |
4 | | |
5 | | #include "qlocalsocket.h" |
6 | | #include "qlocalsocket_p.h" |
7 | | #include "qnet_unix_p.h" |
8 | | |
9 | | #include <sys/types.h> |
10 | | #include <sys/socket.h> |
11 | | #include <sys/un.h> |
12 | | #include <unistd.h> |
13 | | #include <fcntl.h> |
14 | | #include <errno.h> |
15 | | |
16 | | #include <qdir.h> |
17 | | #include <qdeadlinetimer.h> |
18 | | #include <qdebug.h> |
19 | | #include <qstringconverter.h> |
20 | | |
21 | | #ifdef Q_OS_VXWORKS |
22 | | # include <selectLib.h> |
23 | | #endif |
24 | | |
25 | | using namespace std::chrono_literals; |
26 | | |
27 | 0 | #define QT_CONNECT_TIMEOUT 30000 |
28 | | |
29 | | QT_BEGIN_NAMESPACE |
30 | | |
31 | | using namespace Qt::StringLiterals; |
32 | | |
33 | | namespace { |
34 | | // determine the full server path |
35 | | static QString pathNameForConnection(const QString &connectingName, |
36 | | QLocalSocket::SocketOptions options) |
37 | 0 | { |
38 | 0 | if (options.testFlag(QLocalSocket::AbstractNamespaceOption) |
39 | 0 | || connectingName.startsWith(u'/')) { |
40 | 0 | return connectingName; |
41 | 0 | } |
42 | | |
43 | 0 | return QDir::tempPath() + u'/' + connectingName; |
44 | 0 | } |
45 | | |
46 | | static QLocalSocket::SocketOptions optionsForPlatform(QLocalSocket::SocketOptions srcOptions) |
47 | 0 | { |
48 | | // For OS that does not support abstract namespace the AbstractNamespaceOption |
49 | | // option is cleared. |
50 | 0 | if (!PlatformSupportsAbstractNamespace) |
51 | 0 | return QLocalSocket::NoOptions; |
52 | 0 | return srcOptions; |
53 | 0 | } |
54 | | } |
55 | | |
56 | 0 | QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(), |
57 | 0 | delayConnect(nullptr), |
58 | 0 | connectTimer(nullptr), |
59 | 0 | connectingSocket(-1), |
60 | 0 | state(QLocalSocket::UnconnectedState), |
61 | 0 | socketOptions(QLocalSocket::NoOptions) |
62 | 0 | { |
63 | 0 | } |
64 | | |
65 | | void QLocalSocketPrivate::init() |
66 | 0 | { |
67 | 0 | Q_Q(QLocalSocket); |
68 | | // QIODevice signals |
69 | 0 | q->connect(&unixSocket, SIGNAL(bytesWritten(qint64)), |
70 | 0 | q, SIGNAL(bytesWritten(qint64))); |
71 | 0 | q->connect(&unixSocket, SIGNAL(channelBytesWritten(int, qint64)), |
72 | 0 | q, SIGNAL(channelBytesWritten(int, qint64))); |
73 | 0 | q->connect(&unixSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead())); |
74 | 0 | q->connect(&unixSocket, SIGNAL(channelReadyRead(int)), |
75 | 0 | q, SIGNAL(channelReadyRead(int))); |
76 | | // QAbstractSocket signals |
77 | 0 | q->connect(&unixSocket, SIGNAL(connected()), q, SIGNAL(connected())); |
78 | 0 | q->connect(&unixSocket, SIGNAL(disconnected()), q, SIGNAL(disconnected())); |
79 | 0 | q->connect(&unixSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), |
80 | 0 | q, SLOT(_q_stateChanged(QAbstractSocket::SocketState))); |
81 | 0 | q->connect(&unixSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), |
82 | 0 | q, SLOT(_q_errorOccurred(QAbstractSocket::SocketError))); |
83 | 0 | q->connect(&unixSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished())); |
84 | 0 | unixSocket.setParent(q); |
85 | 0 | } |
86 | | |
87 | | void QLocalSocketPrivate::_q_errorOccurred(QAbstractSocket::SocketError socketError) |
88 | 0 | { |
89 | 0 | Q_Q(QLocalSocket); |
90 | 0 | QString function = "QLocalSocket"_L1; |
91 | 0 | QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError; |
92 | 0 | QString errorString = generateErrorString(error, function); |
93 | 0 | q->setErrorString(errorString); |
94 | 0 | emit q->errorOccurred(error); |
95 | 0 | } |
96 | | |
97 | | void QLocalSocketPrivate::_q_stateChanged(QAbstractSocket::SocketState newState) |
98 | 0 | { |
99 | 0 | Q_Q(QLocalSocket); |
100 | 0 | QLocalSocket::LocalSocketState currentState = state; |
101 | 0 | switch(newState) { |
102 | 0 | case QAbstractSocket::UnconnectedState: |
103 | 0 | state = QLocalSocket::UnconnectedState; |
104 | 0 | serverName.clear(); |
105 | 0 | fullServerName.clear(); |
106 | 0 | break; |
107 | 0 | case QAbstractSocket::ConnectingState: |
108 | 0 | state = QLocalSocket::ConnectingState; |
109 | 0 | break; |
110 | 0 | case QAbstractSocket::ConnectedState: |
111 | 0 | state = QLocalSocket::ConnectedState; |
112 | 0 | break; |
113 | 0 | case QAbstractSocket::ClosingState: |
114 | 0 | state = QLocalSocket::ClosingState; |
115 | 0 | break; |
116 | 0 | default: |
117 | | #if defined QLOCALSOCKET_DEBUG |
118 | | qWarning() << "QLocalSocket::Unhandled socket state change:" << newState; |
119 | | #endif |
120 | 0 | return; |
121 | 0 | } |
122 | 0 | if (currentState != state) |
123 | 0 | emit q->stateChanged(state); |
124 | 0 | } |
125 | | |
126 | | QString QLocalSocketPrivate::generateErrorString(QLocalSocket::LocalSocketError error, const QString &function) const |
127 | 0 | { |
128 | 0 | QString errorString; |
129 | 0 | switch (error) { |
130 | 0 | case QLocalSocket::ConnectionRefusedError: |
131 | 0 | errorString = QLocalSocket::tr("%1: Connection refused").arg(function); |
132 | 0 | break; |
133 | 0 | case QLocalSocket::PeerClosedError: |
134 | 0 | errorString = QLocalSocket::tr("%1: Remote closed").arg(function); |
135 | 0 | break; |
136 | 0 | case QLocalSocket::ServerNotFoundError: |
137 | 0 | errorString = QLocalSocket::tr("%1: Invalid name").arg(function); |
138 | 0 | break; |
139 | 0 | case QLocalSocket::SocketAccessError: |
140 | 0 | errorString = QLocalSocket::tr("%1: Socket access error").arg(function); |
141 | 0 | break; |
142 | 0 | case QLocalSocket::SocketResourceError: |
143 | 0 | errorString = QLocalSocket::tr("%1: Socket resource error").arg(function); |
144 | 0 | break; |
145 | 0 | case QLocalSocket::SocketTimeoutError: |
146 | 0 | errorString = QLocalSocket::tr("%1: Socket operation timed out").arg(function); |
147 | 0 | break; |
148 | 0 | case QLocalSocket::DatagramTooLargeError: |
149 | 0 | errorString = QLocalSocket::tr("%1: Datagram too large").arg(function); |
150 | 0 | break; |
151 | 0 | case QLocalSocket::ConnectionError: |
152 | 0 | errorString = QLocalSocket::tr("%1: Connection error").arg(function); |
153 | 0 | break; |
154 | 0 | case QLocalSocket::UnsupportedSocketOperationError: |
155 | 0 | errorString = QLocalSocket::tr("%1: The socket operation is not supported").arg(function); |
156 | 0 | break; |
157 | 0 | case QLocalSocket::OperationError: |
158 | 0 | errorString = QLocalSocket::tr("%1: Operation not permitted when socket is in this state").arg(function); |
159 | 0 | break; |
160 | 0 | case QLocalSocket::UnknownSocketError: |
161 | 0 | default: |
162 | 0 | errorString = QLocalSocket::tr("%1: Unknown error %2").arg(function).arg(errno); |
163 | 0 | } |
164 | 0 | return errorString; |
165 | 0 | } |
166 | | |
167 | | void QLocalSocketPrivate::setErrorAndEmit(QLocalSocket::LocalSocketError error, const QString &function) |
168 | 0 | { |
169 | 0 | Q_Q(QLocalSocket); |
170 | 0 | switch (error) { |
171 | 0 | case QLocalSocket::ConnectionRefusedError: |
172 | 0 | unixSocket.setSocketError(QAbstractSocket::ConnectionRefusedError); |
173 | 0 | break; |
174 | 0 | case QLocalSocket::PeerClosedError: |
175 | 0 | unixSocket.setSocketError(QAbstractSocket::RemoteHostClosedError); |
176 | 0 | break; |
177 | 0 | case QLocalSocket::ServerNotFoundError: |
178 | 0 | unixSocket.setSocketError(QAbstractSocket::HostNotFoundError); |
179 | 0 | break; |
180 | 0 | case QLocalSocket::SocketAccessError: |
181 | 0 | unixSocket.setSocketError(QAbstractSocket::SocketAccessError); |
182 | 0 | break; |
183 | 0 | case QLocalSocket::SocketResourceError: |
184 | 0 | unixSocket.setSocketError(QAbstractSocket::SocketResourceError); |
185 | 0 | break; |
186 | 0 | case QLocalSocket::SocketTimeoutError: |
187 | 0 | unixSocket.setSocketError(QAbstractSocket::SocketTimeoutError); |
188 | 0 | break; |
189 | 0 | case QLocalSocket::DatagramTooLargeError: |
190 | 0 | unixSocket.setSocketError(QAbstractSocket::DatagramTooLargeError); |
191 | 0 | break; |
192 | 0 | case QLocalSocket::ConnectionError: |
193 | 0 | unixSocket.setSocketError(QAbstractSocket::NetworkError); |
194 | 0 | break; |
195 | 0 | case QLocalSocket::UnsupportedSocketOperationError: |
196 | 0 | unixSocket.setSocketError(QAbstractSocket::UnsupportedSocketOperationError); |
197 | 0 | break; |
198 | 0 | case QLocalSocket::UnknownSocketError: |
199 | 0 | default: |
200 | 0 | unixSocket.setSocketError(QAbstractSocket::UnknownSocketError); |
201 | 0 | } |
202 | | |
203 | 0 | QString errorString = generateErrorString(error, function); |
204 | 0 | q->setErrorString(errorString); |
205 | 0 | emit q->errorOccurred(error); |
206 | | |
207 | | // errors cause a disconnect |
208 | 0 | unixSocket.setSocketState(QAbstractSocket::UnconnectedState); |
209 | 0 | bool stateChanged = (state != QLocalSocket::UnconnectedState); |
210 | 0 | state = QLocalSocket::UnconnectedState; |
211 | 0 | q->close(); |
212 | 0 | if (stateChanged) |
213 | 0 | q->emit stateChanged(state); |
214 | 0 | } |
215 | | |
216 | | void QLocalSocket::connectToServer(OpenMode openMode) |
217 | 0 | { |
218 | 0 | Q_D(QLocalSocket); |
219 | 0 | if (state() == ConnectedState || state() == ConnectingState) { |
220 | 0 | QString errorString = d->generateErrorString(QLocalSocket::OperationError, "QLocalSocket::connectToserver"_L1); |
221 | 0 | setErrorString(errorString); |
222 | 0 | emit errorOccurred(QLocalSocket::OperationError); |
223 | 0 | return; |
224 | 0 | } |
225 | | |
226 | 0 | d->errorString.clear(); |
227 | 0 | d->unixSocket.setSocketState(QAbstractSocket::ConnectingState); |
228 | 0 | d->state = ConnectingState; |
229 | 0 | emit stateChanged(d->state); |
230 | |
|
231 | 0 | if (d->serverName.isEmpty()) { |
232 | 0 | d->setErrorAndEmit(ServerNotFoundError, "QLocalSocket::connectToServer"_L1); |
233 | 0 | return; |
234 | 0 | } |
235 | | |
236 | | // create the socket |
237 | 0 | if (-1 == (d->connectingSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0, O_NONBLOCK))) { |
238 | 0 | d->setErrorAndEmit(UnsupportedSocketOperationError, "QLocalSocket::connectToServer"_L1); |
239 | 0 | return; |
240 | 0 | } |
241 | | |
242 | | // _q_connectToSocket does the actual connecting |
243 | 0 | d->connectingName = d->serverName; |
244 | 0 | d->connectingOpenMode = openMode; |
245 | 0 | d->_q_connectToSocket(); |
246 | 0 | return; |
247 | 0 | } |
248 | | |
249 | | /*! |
250 | | \internal |
251 | | |
252 | | Tries to connect connectingName and connectingOpenMode |
253 | | |
254 | | \sa connectToServer(), waitForConnected() |
255 | | */ |
256 | | void QLocalSocketPrivate::_q_connectToSocket() |
257 | 0 | { |
258 | 0 | Q_Q(QLocalSocket); |
259 | |
|
260 | 0 | QLocalSocket::SocketOptions options = optionsForPlatform(socketOptions); |
261 | 0 | const QString connectingPathName = pathNameForConnection(connectingName, options); |
262 | 0 | const QByteArray encodedConnectingPathName = QFile::encodeName(connectingPathName); |
263 | 0 | struct ::sockaddr_un addr; |
264 | 0 | addr.sun_family = PF_UNIX; |
265 | 0 | memset(addr.sun_path, 0, sizeof(addr.sun_path)); |
266 | | |
267 | | // for abstract socket add 2 to length, to take into account trailing AND leading null |
268 | 0 | constexpr unsigned int extraCharacters = PlatformSupportsAbstractNamespace ? 2 : 1; |
269 | |
|
270 | 0 | if (sizeof(addr.sun_path) < static_cast<size_t>(encodedConnectingPathName.size() + extraCharacters)) { |
271 | 0 | QString function = "QLocalSocket::connectToServer"_L1; |
272 | 0 | setErrorAndEmit(QLocalSocket::ServerNotFoundError, function); |
273 | 0 | return; |
274 | 0 | } |
275 | | |
276 | 0 | QT_SOCKLEN_T addrSize = sizeof(::sockaddr_un); |
277 | 0 | if (options.testFlag(QLocalSocket::AbstractNamespaceOption)) { |
278 | 0 | ::memcpy(addr.sun_path + 1, encodedConnectingPathName.constData(), |
279 | 0 | encodedConnectingPathName.size() + 1); |
280 | 0 | addrSize = offsetof(::sockaddr_un, sun_path) + encodedConnectingPathName.size() + 1; |
281 | 0 | } else { |
282 | 0 | ::memcpy(addr.sun_path, encodedConnectingPathName.constData(), |
283 | 0 | encodedConnectingPathName.size() + 1); |
284 | 0 | } |
285 | 0 | if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&addr, addrSize)) { |
286 | 0 | QString function = "QLocalSocket::connectToServer"_L1; |
287 | 0 | switch (errno) |
288 | 0 | { |
289 | 0 | case EINVAL: |
290 | 0 | case ECONNREFUSED: |
291 | 0 | setErrorAndEmit(QLocalSocket::ConnectionRefusedError, function); |
292 | 0 | break; |
293 | 0 | case ENOENT: |
294 | 0 | setErrorAndEmit(QLocalSocket::ServerNotFoundError, function); |
295 | 0 | break; |
296 | 0 | case EACCES: |
297 | 0 | case EPERM: |
298 | 0 | setErrorAndEmit(QLocalSocket::SocketAccessError, function); |
299 | 0 | break; |
300 | 0 | case ETIMEDOUT: |
301 | 0 | setErrorAndEmit(QLocalSocket::SocketTimeoutError, function); |
302 | 0 | break; |
303 | 0 | case EAGAIN: |
304 | | // Try again later, all of the sockets listening are full |
305 | 0 | if (!delayConnect) { |
306 | 0 | delayConnect = new QSocketNotifier(connectingSocket, QSocketNotifier::Write, q); |
307 | 0 | q->connect(delayConnect, SIGNAL(activated(QSocketDescriptor)), q, SLOT(_q_connectToSocket())); |
308 | 0 | } |
309 | 0 | if (!connectTimer) { |
310 | 0 | connectTimer = new QTimer(q); |
311 | 0 | q->connect(connectTimer, SIGNAL(timeout()), |
312 | 0 | q, SLOT(_q_abortConnectionAttempt()), |
313 | 0 | Qt::DirectConnection); |
314 | 0 | connectTimer->start(QT_CONNECT_TIMEOUT); |
315 | 0 | } |
316 | 0 | delayConnect->setEnabled(true); |
317 | 0 | break; |
318 | 0 | default: |
319 | 0 | setErrorAndEmit(QLocalSocket::UnknownSocketError, function); |
320 | 0 | } |
321 | 0 | return; |
322 | 0 | } |
323 | | |
324 | | // connected! |
325 | 0 | cancelDelayedConnect(); |
326 | |
|
327 | 0 | serverName = connectingName; |
328 | 0 | fullServerName = connectingPathName; |
329 | 0 | if (unixSocket.setSocketDescriptor(connectingSocket, |
330 | 0 | QAbstractSocket::ConnectedState, connectingOpenMode)) { |
331 | 0 | q->QIODevice::open(connectingOpenMode); |
332 | 0 | q->emit connected(); |
333 | 0 | } else { |
334 | 0 | QString function = "QLocalSocket::connectToServer"_L1; |
335 | 0 | setErrorAndEmit(QLocalSocket::UnknownSocketError, function); |
336 | 0 | } |
337 | 0 | connectingSocket = -1; |
338 | 0 | connectingName.clear(); |
339 | 0 | connectingOpenMode = { }; |
340 | 0 | } |
341 | | |
342 | | bool QLocalSocket::setSocketDescriptor(qintptr socketDescriptor, |
343 | | LocalSocketState socketState, OpenMode openMode) |
344 | 0 | { |
345 | 0 | Q_D(QLocalSocket); |
346 | 0 | QAbstractSocket::SocketState newSocketState = QAbstractSocket::UnconnectedState; |
347 | 0 | switch (socketState) { |
348 | 0 | case ConnectingState: |
349 | 0 | newSocketState = QAbstractSocket::ConnectingState; |
350 | 0 | break; |
351 | 0 | case ConnectedState: |
352 | 0 | newSocketState = QAbstractSocket::ConnectedState; |
353 | 0 | break; |
354 | 0 | case ClosingState: |
355 | 0 | newSocketState = QAbstractSocket::ClosingState; |
356 | 0 | break; |
357 | 0 | case UnconnectedState: |
358 | 0 | newSocketState = QAbstractSocket::UnconnectedState; |
359 | 0 | break; |
360 | 0 | } |
361 | 0 | QIODevice::open(openMode); |
362 | 0 | d->state = socketState; |
363 | 0 | d->describeSocket(socketDescriptor); |
364 | 0 | const bool result = d->unixSocket.setSocketDescriptor(socketDescriptor, |
365 | 0 | newSocketState, openMode); |
366 | | // Since we directly assigned d->state above, any emission from unixSocket for |
367 | | // state change emission is ignored because the state hasn't changed. So, we |
368 | | // emit it directly here ourselves. |
369 | 0 | if (result) |
370 | 0 | emit stateChanged(d->state); |
371 | 0 | return result; |
372 | 0 | } |
373 | | |
374 | | void QLocalSocketPrivate::describeSocket(qintptr socketDescriptor) |
375 | 0 | { |
376 | 0 | bool abstractAddress = false; |
377 | |
|
378 | 0 | struct ::sockaddr_un addr; |
379 | 0 | QT_SOCKLEN_T len = sizeof(addr); |
380 | 0 | memset(&addr, 0, sizeof(addr)); |
381 | 0 | const int getpeernameStatus = ::getpeername(socketDescriptor, (sockaddr *)&addr, &len); |
382 | 0 | if (getpeernameStatus != 0 || len == offsetof(sockaddr_un, sun_path)) { |
383 | | // this is the case when we call it from QLocalServer, then there is no peername |
384 | 0 | len = sizeof(addr); |
385 | 0 | if (::getsockname(socketDescriptor, (sockaddr *)&addr, &len) != 0) |
386 | 0 | return; |
387 | 0 | } |
388 | 0 | if (parseSockaddr(addr, static_cast<uint>(len), fullServerName, serverName, abstractAddress)) { |
389 | 0 | QLocalSocket::SocketOptions options = socketOptions.value(); |
390 | 0 | socketOptions = options.setFlag(QLocalSocket::AbstractNamespaceOption, abstractAddress); |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | bool QLocalSocketPrivate::parseSockaddr(const struct ::sockaddr_un &addr, |
395 | | uint len, |
396 | | QString &fullServerName, |
397 | | QString &serverName, |
398 | | bool &abstractNamespace) |
399 | 0 | { |
400 | 0 | if (len <= offsetof(::sockaddr_un, sun_path)) |
401 | 0 | return false; |
402 | 0 | len -= offsetof(::sockaddr_un, sun_path); |
403 | | // check for abstract socket address |
404 | 0 | abstractNamespace = PlatformSupportsAbstractNamespace |
405 | 0 | && (addr.sun_family == PF_UNIX && addr.sun_path[0] == 0); |
406 | 0 | QStringDecoder toUtf16(QStringDecoder::System, QStringDecoder::Flag::Stateless); |
407 | | // An abstract socket address can be arbitrary binary. To properly handle such a case, |
408 | | // we'd have to add new access functions for this very specific case. Instead, we just |
409 | | // attempt to decode it according to OS text encoding. If it fails we ignore the result. |
410 | 0 | QByteArrayView textData(addr.sun_path + (abstractNamespace ? 1 : 0), |
411 | 0 | len - (abstractNamespace ? 1 : 0)); |
412 | 0 | QString name = toUtf16(textData); |
413 | 0 | if (!name.isEmpty() && !toUtf16.hasError()) { |
414 | | //conversion encodes the trailing zeros. So, in case of non-abstract namespace we |
415 | | //chop them off as \0 character is not allowed in filenames |
416 | 0 | if (!abstractNamespace && (name.at(name.size() - 1) == QChar::fromLatin1('\0'))) { |
417 | 0 | int truncPos = name.size() - 1; |
418 | 0 | while (truncPos > 0 && name.at(truncPos - 1) == QChar::fromLatin1('\0')) |
419 | 0 | truncPos--; |
420 | 0 | name.truncate(truncPos); |
421 | 0 | } |
422 | 0 | fullServerName = name; |
423 | 0 | serverName = abstractNamespace |
424 | 0 | ? name |
425 | 0 | : fullServerName.mid(fullServerName.lastIndexOf(u'/') + 1); |
426 | 0 | if (serverName.isEmpty()) |
427 | 0 | serverName = fullServerName; |
428 | 0 | } |
429 | 0 | return true; |
430 | 0 | } |
431 | | |
432 | | void QLocalSocketPrivate::_q_abortConnectionAttempt() |
433 | 0 | { |
434 | 0 | Q_Q(QLocalSocket); |
435 | 0 | q->close(); |
436 | 0 | } |
437 | | |
438 | | void QLocalSocketPrivate::cancelDelayedConnect() |
439 | 0 | { |
440 | 0 | if (delayConnect) { |
441 | 0 | delayConnect->setEnabled(false); |
442 | 0 | delete delayConnect; |
443 | 0 | delayConnect = nullptr; |
444 | 0 | connectTimer->stop(); |
445 | 0 | delete connectTimer; |
446 | 0 | connectTimer = nullptr; |
447 | 0 | } |
448 | 0 | } |
449 | | |
450 | | qintptr QLocalSocket::socketDescriptor() const |
451 | 0 | { |
452 | 0 | Q_D(const QLocalSocket); |
453 | 0 | return d->unixSocket.socketDescriptor(); |
454 | 0 | } |
455 | | |
456 | | qint64 QLocalSocket::readData(char *data, qint64 c) |
457 | 0 | { |
458 | 0 | Q_D(QLocalSocket); |
459 | 0 | return d->unixSocket.read(data, c); |
460 | 0 | } |
461 | | |
462 | | qint64 QLocalSocket::readLineData(char *data, qint64 maxSize) |
463 | 0 | { |
464 | 0 | if (!maxSize) |
465 | 0 | return 0; |
466 | | |
467 | | // QIODevice::readLine() reserves space for the trailing '\0' byte, |
468 | | // so we must read 'maxSize + 1' bytes. |
469 | 0 | return d_func()->unixSocket.readLine(data, maxSize + 1); |
470 | 0 | } |
471 | | |
472 | | qint64 QLocalSocket::skipData(qint64 maxSize) |
473 | 0 | { |
474 | 0 | return d_func()->unixSocket.skip(maxSize); |
475 | 0 | } |
476 | | |
477 | | qint64 QLocalSocket::writeData(const char *data, qint64 c) |
478 | 0 | { |
479 | 0 | Q_D(QLocalSocket); |
480 | 0 | return d->unixSocket.writeData(data, c); |
481 | 0 | } |
482 | | |
483 | | void QLocalSocket::abort() |
484 | 0 | { |
485 | 0 | Q_D(QLocalSocket); |
486 | 0 | d->unixSocket.abort(); |
487 | 0 | close(); |
488 | 0 | } |
489 | | |
490 | | qint64 QLocalSocket::bytesAvailable() const |
491 | 0 | { |
492 | 0 | Q_D(const QLocalSocket); |
493 | 0 | return QIODevice::bytesAvailable() + d->unixSocket.bytesAvailable(); |
494 | 0 | } |
495 | | |
496 | | qint64 QLocalSocket::bytesToWrite() const |
497 | 0 | { |
498 | 0 | Q_D(const QLocalSocket); |
499 | 0 | return d->unixSocket.bytesToWrite(); |
500 | 0 | } |
501 | | |
502 | | bool QLocalSocket::canReadLine() const |
503 | 0 | { |
504 | 0 | Q_D(const QLocalSocket); |
505 | 0 | return QIODevice::canReadLine() || d->unixSocket.canReadLine(); |
506 | 0 | } |
507 | | |
508 | | void QLocalSocket::close() |
509 | 0 | { |
510 | 0 | Q_D(QLocalSocket); |
511 | |
|
512 | 0 | QIODevice::close(); |
513 | 0 | d->unixSocket.close(); |
514 | 0 | d->cancelDelayedConnect(); |
515 | 0 | if (d->connectingSocket != -1) |
516 | 0 | ::close(d->connectingSocket); |
517 | 0 | d->connectingSocket = -1; |
518 | 0 | d->connectingName.clear(); |
519 | 0 | d->connectingOpenMode = { }; |
520 | 0 | d->serverName.clear(); |
521 | 0 | d->fullServerName.clear(); |
522 | 0 | } |
523 | | |
524 | | bool QLocalSocket::waitForBytesWritten(int msecs) |
525 | 0 | { |
526 | 0 | Q_D(QLocalSocket); |
527 | 0 | return d->unixSocket.waitForBytesWritten(msecs); |
528 | 0 | } |
529 | | |
530 | | bool QLocalSocket::flush() |
531 | 0 | { |
532 | 0 | Q_D(QLocalSocket); |
533 | 0 | return d->unixSocket.flush(); |
534 | 0 | } |
535 | | |
536 | | void QLocalSocket::disconnectFromServer() |
537 | 0 | { |
538 | 0 | Q_D(QLocalSocket); |
539 | 0 | d->unixSocket.disconnectFromHost(); |
540 | 0 | } |
541 | | |
542 | | QLocalSocket::LocalSocketError QLocalSocket::error() const |
543 | 0 | { |
544 | 0 | Q_D(const QLocalSocket); |
545 | 0 | switch (d->unixSocket.error()) { |
546 | 0 | case QAbstractSocket::ConnectionRefusedError: |
547 | 0 | return QLocalSocket::ConnectionRefusedError; |
548 | 0 | case QAbstractSocket::RemoteHostClosedError: |
549 | 0 | return QLocalSocket::PeerClosedError; |
550 | 0 | case QAbstractSocket::HostNotFoundError: |
551 | 0 | return QLocalSocket::ServerNotFoundError; |
552 | 0 | case QAbstractSocket::SocketAccessError: |
553 | 0 | return QLocalSocket::SocketAccessError; |
554 | 0 | case QAbstractSocket::SocketResourceError: |
555 | 0 | return QLocalSocket::SocketResourceError; |
556 | 0 | case QAbstractSocket::SocketTimeoutError: |
557 | 0 | return QLocalSocket::SocketTimeoutError; |
558 | 0 | case QAbstractSocket::DatagramTooLargeError: |
559 | 0 | return QLocalSocket::DatagramTooLargeError; |
560 | 0 | case QAbstractSocket::NetworkError: |
561 | 0 | return QLocalSocket::ConnectionError; |
562 | 0 | case QAbstractSocket::UnsupportedSocketOperationError: |
563 | 0 | return QLocalSocket::UnsupportedSocketOperationError; |
564 | 0 | case QAbstractSocket::UnknownSocketError: |
565 | 0 | return QLocalSocket::UnknownSocketError; |
566 | 0 | default: |
567 | | #if defined QLOCALSOCKET_DEBUG |
568 | | qWarning() << "QLocalSocket error not handled:" << d->unixSocket.error(); |
569 | | #endif |
570 | 0 | break; |
571 | 0 | } |
572 | 0 | return UnknownSocketError; |
573 | 0 | } |
574 | | |
575 | | bool QLocalSocket::isValid() const |
576 | 0 | { |
577 | 0 | Q_D(const QLocalSocket); |
578 | 0 | return d->unixSocket.isValid(); |
579 | 0 | } |
580 | | |
581 | | qint64 QLocalSocket::readBufferSize() const |
582 | 0 | { |
583 | 0 | Q_D(const QLocalSocket); |
584 | 0 | return d->unixSocket.readBufferSize(); |
585 | 0 | } |
586 | | |
587 | | void QLocalSocket::setReadBufferSize(qint64 size) |
588 | 0 | { |
589 | 0 | Q_D(QLocalSocket); |
590 | 0 | d->unixSocket.setReadBufferSize(size); |
591 | 0 | } |
592 | | |
593 | | bool QLocalSocket::waitForConnected(int msec) |
594 | 0 | { |
595 | 0 | Q_D(QLocalSocket); |
596 | |
|
597 | 0 | if (state() != ConnectingState) |
598 | 0 | return (state() == ConnectedState); |
599 | | |
600 | 0 | pollfd pfd = qt_make_pollfd(d->connectingSocket, POLLIN); |
601 | |
|
602 | 0 | QDeadlineTimer deadline{msec}; |
603 | 0 | auto remainingTime = deadline.remainingTimeAsDuration(); |
604 | |
|
605 | 0 | do { |
606 | 0 | const int result = qt_safe_poll(&pfd, 1, deadline); |
607 | 0 | if (result == -1) |
608 | 0 | d->setErrorAndEmit(QLocalSocket::UnknownSocketError, |
609 | 0 | "QLocalSocket::waitForConnected"_L1); |
610 | 0 | else if (result > 0) |
611 | 0 | d->_q_connectToSocket(); |
612 | 0 | } while (state() == ConnectingState |
613 | 0 | && (remainingTime = deadline.remainingTimeAsDuration()) > 0ns); |
614 | |
|
615 | 0 | return (state() == ConnectedState); |
616 | 0 | } |
617 | | |
618 | | bool QLocalSocket::waitForDisconnected(int msecs) |
619 | 0 | { |
620 | 0 | Q_D(QLocalSocket); |
621 | 0 | if (state() == UnconnectedState) { |
622 | 0 | qWarning("QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState"); |
623 | 0 | return false; |
624 | 0 | } |
625 | 0 | return (d->unixSocket.waitForDisconnected(msecs)); |
626 | 0 | } |
627 | | |
628 | | bool QLocalSocket::waitForReadyRead(int msecs) |
629 | 0 | { |
630 | 0 | Q_D(QLocalSocket); |
631 | 0 | if (state() == QLocalSocket::UnconnectedState) |
632 | 0 | return false; |
633 | 0 | return (d->unixSocket.waitForReadyRead(msecs)); |
634 | 0 | } |
635 | | |
636 | | QT_END_NAMESPACE |