Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qlocalsocket_tcp.cpp
Go to the documentation of this file.
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"
7#include "qlocalserver.h"
8
9#include <qhostaddress.h>
10#include <qsettings.h>
11#include <qdebug.h>
12
14
15using namespace Qt::StringLiterals;
16
17QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
18 tcpSocket(0),
19 ownsTcpSocket(true),
20 state(QLocalSocket::UnconnectedState)
21{
22}
23
25{
26 setSocket(new QLocalUnixSocket);
27}
28
29void QLocalSocketPrivate::setSocket(QLocalUnixSocket* socket)
30{
31 if (ownsTcpSocket)
32 delete tcpSocket;
33 ownsTcpSocket = false;
34 tcpSocket = socket;
35
36 Q_Q(QLocalSocket);
37 // QIODevice signals
38 q->connect(tcpSocket, SIGNAL(bytesWritten(qint64)),
39 q, SIGNAL(bytesWritten(qint64)));
40 q->connect(tcpSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
41 // QAbstractSocket signals
42 q->connect(tcpSocket, SIGNAL(connected()), q, SIGNAL(connected()));
43 q->connect(tcpSocket, SIGNAL(disconnected()), q, SIGNAL(disconnected()));
44 q->connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
45 q, SLOT(_q_stateChanged(QAbstractSocket::SocketState)));
46 q->connect(tcpSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
47 q, SLOT(_q_errorOccurred(QAbstractSocket::SocketError)));
48 q->connect(tcpSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));
49 tcpSocket->setParent(q);
50}
51
52void QLocalSocketPrivate::_q_errorOccurred(QAbstractSocket::SocketError socketError)
53{
54 Q_Q(QLocalSocket);
55 QString function = "QLocalSocket"_L1;
56 QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError;
57 QString errorString = generateErrorString(error, function);
58 q->setErrorString(errorString);
59 emit q->errorOccurred(error);
60}
61
62void QLocalSocketPrivate::_q_stateChanged(QAbstractSocket::SocketState newState)
63{
64 Q_Q(QLocalSocket);
65 QLocalSocket::LocalSocketState currentState = state;
66 switch(newState) {
67 case QAbstractSocket::UnconnectedState:
68 state = QLocalSocket::UnconnectedState;
69 serverName.clear();
70 fullServerName.clear();
71 break;
72 case QAbstractSocket::ConnectingState:
73 state = QLocalSocket::ConnectingState;
74 break;
75 case QAbstractSocket::ConnectedState:
76 state = QLocalSocket::ConnectedState;
77 break;
78 case QAbstractSocket::ClosingState:
79 state = QLocalSocket::ClosingState;
80 break;
81 default:
82#if defined QLOCALSOCKET_DEBUG
83 qWarning() << "QLocalSocket::Unhandled socket state change:" << newState;
84#endif
85 return;
86 }
87 if (currentState != state)
88 emit q->stateChanged(state);
89}
90
91QString QLocalSocketPrivate::generateErrorString(QLocalSocket::LocalSocketError error, const QString &function) const
92{
93 QString errorString;
94 switch (error) {
95 case QLocalSocket::ConnectionRefusedError:
96 errorString = QLocalSocket::tr("%1: Connection refused").arg(function);
97 break;
98 case QLocalSocket::PeerClosedError:
99 errorString = QLocalSocket::tr("%1: Remote closed").arg(function);
100 break;
101 case QLocalSocket::ServerNotFoundError:
102 errorString = QLocalSocket::tr("%1: Invalid name").arg(function);
103 break;
104 case QLocalSocket::SocketAccessError:
105 errorString = QLocalSocket::tr("%1: Socket access error").arg(function);
106 break;
107 case QLocalSocket::SocketResourceError:
108 errorString = QLocalSocket::tr("%1: Socket resource error").arg(function);
109 break;
110 case QLocalSocket::SocketTimeoutError:
111 errorString = QLocalSocket::tr("%1: Socket operation timed out").arg(function);
112 break;
113 case QLocalSocket::DatagramTooLargeError:
114 errorString = QLocalSocket::tr("%1: Datagram too large").arg(function);
115 break;
116 case QLocalSocket::ConnectionError:
117 errorString = QLocalSocket::tr("%1: Connection error").arg(function);
118 break;
119 case QLocalSocket::UnsupportedSocketOperationError:
120 errorString = QLocalSocket::tr("%1: The socket operation is not supported").arg(function);
121 break;
122 case QLocalSocket::OperationError:
123 errorString = QLocalSocket::tr("%1: Operation not permitted when socket is in this state").arg(function);
124 break;
125 case QLocalSocket::UnknownSocketError:
126 default:
127 errorString = QLocalSocket::tr("%1: Unknown error").arg(function);
128 }
129 return errorString;
130}
131
132void QLocalSocketPrivate::setErrorAndEmit(QLocalSocket::LocalSocketError error, const QString &function)
133{
134 Q_Q(QLocalSocket);
135 switch (error) {
136 case QLocalSocket::ConnectionRefusedError:
137 tcpSocket->setSocketError(QAbstractSocket::ConnectionRefusedError);
138 break;
139 case QLocalSocket::PeerClosedError:
140 tcpSocket->setSocketError(QAbstractSocket::RemoteHostClosedError);
141 break;
142 case QLocalSocket::ServerNotFoundError:
143 tcpSocket->setSocketError(QAbstractSocket::HostNotFoundError);
144 break;
145 case QLocalSocket::SocketAccessError:
146 tcpSocket->setSocketError(QAbstractSocket::SocketAccessError);
147 break;
148 case QLocalSocket::SocketResourceError:
149 tcpSocket->setSocketError(QAbstractSocket::SocketResourceError);
150 break;
151 case QLocalSocket::SocketTimeoutError:
152 tcpSocket->setSocketError(QAbstractSocket::SocketTimeoutError);
153 break;
154 case QLocalSocket::DatagramTooLargeError:
155 tcpSocket->setSocketError(QAbstractSocket::DatagramTooLargeError);
156 break;
157 case QLocalSocket::ConnectionError:
158 tcpSocket->setSocketError(QAbstractSocket::NetworkError);
159 break;
160 case QLocalSocket::UnsupportedSocketOperationError:
161 tcpSocket->setSocketError(QAbstractSocket::UnsupportedSocketOperationError);
162 break;
163 case QLocalSocket::UnknownSocketError:
164 default:
165 tcpSocket->setSocketError(QAbstractSocket::UnknownSocketError);
166 }
167
168 QString errorString = generateErrorString(error, function);
169 q->setErrorString(errorString);
170 emit q->errorOccurred(error);
171
172 // errors cause a disconnect
173 tcpSocket->setSocketState(QAbstractSocket::UnconnectedState);
174 bool stateChanged = (state != QLocalSocket::UnconnectedState);
175 state = QLocalSocket::UnconnectedState;
176 q->close();
177 if (stateChanged)
178 q->emit stateChanged(state);
179}
180
181void QLocalSocket::connectToServer(OpenMode openMode)
182{
183 Q_D(QLocalSocket);
184 if (state() == ConnectedState || state() == ConnectingState) {
185 setErrorString(tr("Trying to connect while connection is in progress"));
186 emit errorOccurred(QLocalSocket::OperationError);
187 return;
188 }
189
190 d->errorString.clear();
191 d->state = ConnectingState;
192 emit stateChanged(d->state);
193
194 if (d->serverName.isEmpty()) {
195 d->setErrorAndEmit(ServerNotFoundError, "QLocalSocket::connectToServer"_L1);
196 return;
197 }
198
199 const auto prefix = "QLocalServer/"_L1;
200 if (d->serverName.startsWith(prefix))
201 d->fullServerName = d->serverName;
202 else
203 d->fullServerName = prefix + d->serverName;
204
205 QSettings settings("QtProject"_L1, "Qt"_L1);
206 bool ok;
207 const quint16 port = settings.value(d->fullServerName).toUInt(&ok);
208 if (!ok) {
209 d->setErrorAndEmit(ServerNotFoundError, "QLocalSocket::connectToServer"_L1);
210 return;
211 }
212 QIODevice::open(openMode);
213 d->tcpSocket->connectToHost(QHostAddress::LocalHost, port, openMode);
214}
215
216bool QLocalSocket::setSocketDescriptor(qintptr socketDescriptor,
217 LocalSocketState socketState, OpenMode openMode)
218{
219 Q_D(QLocalSocket);
220 QAbstractSocket::SocketState newSocketState = QAbstractSocket::UnconnectedState;
221 switch (socketState) {
222 case ConnectingState:
223 newSocketState = QAbstractSocket::ConnectingState;
224 break;
225 case ConnectedState:
226 newSocketState = QAbstractSocket::ConnectedState;
227 break;
228 case ClosingState:
229 newSocketState = QAbstractSocket::ClosingState;
230 break;
231 case UnconnectedState:
232 newSocketState = QAbstractSocket::UnconnectedState;
233 break;
234 }
235 QIODevice::open(openMode);
236 d->state = socketState;
237
238 // Is our parent a localServer? Then it wants us to use its remote socket.
239 QLocalServer* localServer = qobject_cast<QLocalServer*>( parent() );
240 if (localServer) {
241 for (QObject* child : localServer->children()) {
242 QTcpSocket* childTcpSocket = qobject_cast<QTcpSocket*>(child);
243 if (childTcpSocket && childTcpSocket->socketDescriptor() == socketDescriptor) {
244 d->setSocket( static_cast<QLocalUnixSocket*>(childTcpSocket) );
245 return true;
246 }
247 }
248 }
249
250 // We couldn't find the socket in the children list of our server.
251 // So it might be that the user wants to set a socket descriptor.
252 return d->tcpSocket->setSocketDescriptor(socketDescriptor,
253 newSocketState, openMode);
254}
255
256qintptr QLocalSocket::socketDescriptor() const
257{
258 Q_D(const QLocalSocket);
259 return d->tcpSocket->socketDescriptor();
260}
261
262qint64 QLocalSocket::readData(char *data, qint64 c)
263{
264 Q_D(QLocalSocket);
265 return d->tcpSocket->read(data, c);
266}
267
268qint64 QLocalSocket::readLineData(char *data, qint64 maxSize)
269{
270 if (!maxSize)
271 return 0;
272
273 // QIODevice::readLine() reserves space for the trailing '\0' byte,
274 // so we must read 'maxSize + 1' bytes.
275 return d_func()->tcpSocket->readLine(data, maxSize + 1);
276}
277
278qint64 QLocalSocket::skipData(qint64 maxSize)
279{
280 return d_func()->tcpSocket->skip(maxSize);
281}
282
283qint64 QLocalSocket::writeData(const char *data, qint64 c)
284{
285 Q_D(QLocalSocket);
286 return d->tcpSocket->writeData(data, c);
287}
288
289void QLocalSocket::abort()
290{
291 Q_D(QLocalSocket);
292 d->tcpSocket->abort();
293 close();
294}
295
296qint64 QLocalSocket::bytesAvailable() const
297{
298 Q_D(const QLocalSocket);
299 return QIODevice::bytesAvailable() + d->tcpSocket->bytesAvailable();
300}
301
302qint64 QLocalSocket::bytesToWrite() const
303{
304 Q_D(const QLocalSocket);
305 return d->tcpSocket->bytesToWrite();
306}
307
308bool QLocalSocket::canReadLine() const
309{
310 Q_D(const QLocalSocket);
311 return QIODevice::canReadLine() || d->tcpSocket->canReadLine();
312}
313
314void QLocalSocket::close()
315{
316 Q_D(QLocalSocket);
317
318 QIODevice::close();
319 d->tcpSocket->close();
320 d->serverName.clear();
321 d->fullServerName.clear();
322}
323
324bool QLocalSocket::waitForBytesWritten(int msecs)
325{
326 Q_D(QLocalSocket);
327 return d->tcpSocket->waitForBytesWritten(msecs);
328}
329
330bool QLocalSocket::flush()
331{
332 Q_D(QLocalSocket);
333 return d->tcpSocket->flush();
334}
335
336void QLocalSocket::disconnectFromServer()
337{
338 Q_D(QLocalSocket);
339 d->tcpSocket->disconnectFromHost();
340}
341
342QLocalSocket::LocalSocketError QLocalSocket::error() const
343{
344 Q_D(const QLocalSocket);
345 switch (d->tcpSocket->error()) {
346 case QAbstractSocket::ConnectionRefusedError:
347 return QLocalSocket::ConnectionRefusedError;
348 case QAbstractSocket::RemoteHostClosedError:
349 return QLocalSocket::PeerClosedError;
350 case QAbstractSocket::HostNotFoundError:
351 return QLocalSocket::ServerNotFoundError;
352 case QAbstractSocket::SocketAccessError:
353 return QLocalSocket::SocketAccessError;
354 case QAbstractSocket::SocketResourceError:
355 return QLocalSocket::SocketResourceError;
356 case QAbstractSocket::SocketTimeoutError:
357 return QLocalSocket::SocketTimeoutError;
358 case QAbstractSocket::DatagramTooLargeError:
359 return QLocalSocket::DatagramTooLargeError;
360 case QAbstractSocket::NetworkError:
361 return QLocalSocket::ConnectionError;
362 case QAbstractSocket::UnsupportedSocketOperationError:
363 return QLocalSocket::UnsupportedSocketOperationError;
364 case QAbstractSocket::UnknownSocketError:
365 return QLocalSocket::UnknownSocketError;
366 default:
367#if defined QLOCALSOCKET_DEBUG
368 qWarning() << "QLocalSocket error not handled:" << d->tcpSocket->error();
369#endif
370 break;
371 }
372 return UnknownSocketError;
373}
374
375bool QLocalSocket::isValid() const
376{
377 Q_D(const QLocalSocket);
378 return d->tcpSocket->isValid();
379}
380
381qint64 QLocalSocket::readBufferSize() const
382{
383 Q_D(const QLocalSocket);
384 return d->tcpSocket->readBufferSize();
385}
386
387void QLocalSocket::setReadBufferSize(qint64 size)
388{
389 Q_D(QLocalSocket);
390 d->tcpSocket->setReadBufferSize(size);
391}
392
393bool QLocalSocket::waitForConnected(int msec)
394{
395 Q_D(QLocalSocket);
396 if (state() != ConnectingState)
397 return (state() == ConnectedState);
398
399 return d->tcpSocket->waitForConnected(msec);
400}
401
402bool QLocalSocket::waitForDisconnected(int msecs)
403{
404 Q_D(QLocalSocket);
405 if (state() == UnconnectedState) {
406 qWarning("QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState");
407 return false;
408 }
409 return (d->tcpSocket->waitForDisconnected(msecs));
410}
411
412bool QLocalSocket::waitForReadyRead(int msecs)
413{
414 Q_D(QLocalSocket);
415 if (state() == QLocalSocket::UnconnectedState)
416 return false;
417 return (d->tcpSocket->waitForReadyRead(msecs));
418}
419
420QT_END_NAMESPACE
void _q_stateChanged(QAbstractSocket::SocketState newState)
void _q_errorOccurred(QAbstractSocket::SocketError newError)
void setErrorAndEmit(QLocalSocket::LocalSocketError, const QString &function)
QString generateErrorString(QLocalSocket::LocalSocketError, const QString &function) const