Qt 4.8
qlocalsocket_unix.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qlocalsocket.h"
43 #include "qlocalsocket_p.h"
44 #include "qnet_unix_p.h"
45 
46 #ifndef QT_NO_LOCALSOCKET
47 
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <sys/un.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <errno.h>
54 
55 #include <qdir.h>
56 #include <qdebug.h>
57 #include <qelapsedtimer.h>
58 
59 #ifdef Q_OS_VXWORKS
60 # include <selectLib.h>
61 #endif
62 
63 #define QT_CONNECT_TIMEOUT 30000
64 
66 
68  delayConnect(0),
69  connectTimer(0),
70  connectingSocket(-1),
71  connectingOpenMode(0),
72  state(QLocalSocket::UnconnectedState)
73 {
74 }
75 
77 {
79  // QIODevice signals
80  q->connect(&unixSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));
81  q->connect(&unixSocket, SIGNAL(bytesWritten(qint64)),
82  q, SIGNAL(bytesWritten(qint64)));
83  q->connect(&unixSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
84  // QAbstractSocket signals
85  q->connect(&unixSocket, SIGNAL(connected()), q, SIGNAL(connected()));
86  q->connect(&unixSocket, SIGNAL(disconnected()), q, SIGNAL(disconnected()));
87  q->connect(&unixSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
88  q, SLOT(_q_stateChanged(QAbstractSocket::SocketState)));
89  q->connect(&unixSocket, SIGNAL(error(QAbstractSocket::SocketError)),
90  q, SLOT(_q_error(QAbstractSocket::SocketError)));
91  q->connect(&unixSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));
92  unixSocket.setParent(q);
93 }
94 
95 void QLocalSocketPrivate::_q_error(QAbstractSocket::SocketError socketError)
96 {
98  QString function = QLatin1String("QLocalSocket");
100  QString errorString = generateErrorString(error, function);
101  q->setErrorString(errorString);
102  emit q->error(error);
103 }
104 
105 void QLocalSocketPrivate::_q_stateChanged(QAbstractSocket::SocketState newState)
106 {
107  Q_Q(QLocalSocket);
108  QLocalSocket::LocalSocketState currentState = state;
109  switch(newState) {
112  serverName.clear();
114  break;
117  break;
120  break;
123  break;
124  default:
125 #if defined QLOCALSOCKET_DEBUG
126  qWarning() << "QLocalSocket::Unhandled socket state change:" << newState;
127 #endif
128  return;
129  }
130  if (currentState != state)
131  emit q->stateChanged(state);
132 }
133 
134 QString QLocalSocketPrivate::generateErrorString(QLocalSocket::LocalSocketError error, const QString &function) const
135 {
137  switch (error) {
139  errorString = QLocalSocket::tr("%1: Connection refused").arg(function);
140  break;
142  errorString = QLocalSocket::tr("%1: Remote closed").arg(function);
143  break;
145  errorString = QLocalSocket::tr("%1: Invalid name").arg(function);
146  break;
148  errorString = QLocalSocket::tr("%1: Socket access error").arg(function);
149  break;
151  errorString = QLocalSocket::tr("%1: Socket resource error").arg(function);
152  break;
154  errorString = QLocalSocket::tr("%1: Socket operation timed out").arg(function);
155  break;
157  errorString = QLocalSocket::tr("%1: Datagram too large").arg(function);
158  break;
160  errorString = QLocalSocket::tr("%1: Connection error").arg(function);
161  break;
163  errorString = QLocalSocket::tr("%1: The socket operation is not supported").arg(function);
164  break;
166  default:
167  errorString = QLocalSocket::tr("%1: Unknown error %2").arg(function).arg(errno);
168  }
169  return errorString;
170 }
171 
172 void QLocalSocketPrivate::errorOccurred(QLocalSocket::LocalSocketError error, const QString &function)
173 {
174  Q_Q(QLocalSocket);
175  switch (error) {
177  unixSocket.setSocketError(QAbstractSocket::ConnectionRefusedError);
178  break;
180  unixSocket.setSocketError(QAbstractSocket::RemoteHostClosedError);
181  break;
183  unixSocket.setSocketError(QAbstractSocket::HostNotFoundError);
184  break;
186  unixSocket.setSocketError(QAbstractSocket::SocketAccessError);
187  break;
189  unixSocket.setSocketError(QAbstractSocket::SocketResourceError);
190  break;
192  unixSocket.setSocketError(QAbstractSocket::SocketTimeoutError);
193  break;
195  unixSocket.setSocketError(QAbstractSocket::DatagramTooLargeError);
196  break;
198  unixSocket.setSocketError(QAbstractSocket::NetworkError);
199  break;
201  unixSocket.setSocketError(QAbstractSocket::UnsupportedSocketOperationError);
202  break;
204  default:
205  unixSocket.setSocketError(QAbstractSocket::UnknownSocketError);
206  }
207 
208  QString errorString = generateErrorString(error, function);
209  q->setErrorString(errorString);
210  emit q->error(error);
211 
212  // errors cause a disconnect
213  unixSocket.setSocketState(QAbstractSocket::UnconnectedState);
214  bool stateChanged = (state != QLocalSocket::UnconnectedState);
216  q->close();
217  if (stateChanged)
218  q->emit stateChanged(state);
219 }
220 
221 void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
222 {
223  Q_D(QLocalSocket);
224  if (state() == ConnectedState
225  || state() == ConnectingState)
226  return;
227 
228  d->errorString.clear();
229  d->unixSocket.setSocketState(QAbstractSocket::ConnectingState);
230  d->state = ConnectingState;
231  emit stateChanged(d->state);
232 
233  if (name.isEmpty()) {
234  d->errorOccurred(ServerNotFoundError,
235  QLatin1String("QLocalSocket::connectToServer"));
236  return;
237  }
238 
239  // create the socket
240  if (-1 == (d->connectingSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0))) {
241  d->errorOccurred(UnsupportedSocketOperationError,
242  QLatin1String("QLocalSocket::connectToServer"));
243  return;
244  }
245 #ifndef Q_OS_SYMBIAN
246  // set non blocking so we can try to connect and it wont wait
247  int flags = fcntl(d->connectingSocket, F_GETFL, 0);
248  if (-1 == flags
249  || -1 == (fcntl(d->connectingSocket, F_SETFL, flags | O_NONBLOCK))) {
250  d->errorOccurred(UnknownSocketError,
251  QLatin1String("QLocalSocket::connectToServer"));
252  return;
253  }
254 #endif
255 
256  // _q_connectToSocket does the actual connecting
257  d->connectingName = name;
258  d->connectingOpenMode = openMode;
259  d->_q_connectToSocket();
260 }
261 
269 void QLocalSocketPrivate::_q_connectToSocket()
270 {
271  Q_Q(QLocalSocket);
272  QString connectingPathName;
273 
274  // determine the full server path
275  if (connectingName.startsWith(QLatin1Char('/'))) {
276  connectingPathName = connectingName;
277  } else {
278  connectingPathName = QDir::tempPath();
279  connectingPathName += QLatin1Char('/') + connectingName;
280  }
281 
282  struct sockaddr_un name;
283  name.sun_family = PF_UNIX;
284  if (sizeof(name.sun_path) < (uint)connectingPathName.toLatin1().size() + 1) {
285  QString function = QLatin1String("QLocalSocket::connectToServer");
286  errorOccurred(QLocalSocket::ServerNotFoundError, function);
287  return;
288  }
289  ::memcpy(name.sun_path, connectingPathName.toLatin1().data(),
290  connectingPathName.toLatin1().size() + 1);
291  if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) {
292  QString function = QLatin1String("QLocalSocket::connectToServer");
293  switch (errno)
294  {
295  case EINVAL:
296  case ECONNREFUSED:
297  errorOccurred(QLocalSocket::ConnectionRefusedError, function);
298  break;
299  case ENOENT:
300  errorOccurred(QLocalSocket::ServerNotFoundError, function);
301  break;
302  case EACCES:
303  case EPERM:
304  errorOccurred(QLocalSocket::SocketAccessError, function);
305  break;
306  case ETIMEDOUT:
307  errorOccurred(QLocalSocket::SocketTimeoutError, function);
308  break;
309  case EAGAIN:
310  // Try again later, all of the sockets listening are full
311  if (!delayConnect) {
312  delayConnect = new QSocketNotifier(connectingSocket, QSocketNotifier::Write, q);
313  q->connect(delayConnect, SIGNAL(activated(int)), q, SLOT(_q_connectToSocket()));
314  }
315  if (!connectTimer) {
316  connectTimer = new QTimer(q);
317  q->connect(connectTimer, SIGNAL(timeout()),
318  q, SLOT(_q_abortConnectionAttempt()),
320  connectTimer->start(QT_CONNECT_TIMEOUT);
321  }
322  delayConnect->setEnabled(true);
323  break;
324  default:
325  errorOccurred(QLocalSocket::UnknownSocketError, function);
326  }
327  return;
328  }
329 
330  // connected!
331  cancelDelayedConnect();
332 
333  serverName = connectingName;
334  fullServerName = connectingPathName;
335  if (unixSocket.setSocketDescriptor(connectingSocket,
336  QAbstractSocket::ConnectedState, connectingOpenMode)) {
337  q->QIODevice::open(connectingOpenMode);
338  q->emit connected();
339  } else {
340  QString function = QLatin1String("QLocalSocket::connectToServer");
341  errorOccurred(QLocalSocket::UnknownSocketError, function);
342  }
343  connectingSocket = -1;
344  connectingName.clear();
345  connectingOpenMode = 0;
346 }
347 
348 bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
349  LocalSocketState socketState, OpenMode openMode)
350 {
351  Q_D(QLocalSocket);
353  switch (socketState) {
354  case ConnectingState:
355  newSocketState = QAbstractSocket::ConnectingState;
356  break;
357  case ConnectedState:
358  newSocketState = QAbstractSocket::ConnectedState;
359  break;
360  case ClosingState:
361  newSocketState = QAbstractSocket::ClosingState;
362  break;
363  case UnconnectedState:
364  newSocketState = QAbstractSocket::UnconnectedState;
365  break;
366  }
367  QIODevice::open(openMode);
368  d->state = socketState;
369  return d->unixSocket.setSocketDescriptor(socketDescriptor,
370  newSocketState, openMode);
371 }
372 
373 void QLocalSocketPrivate::_q_abortConnectionAttempt()
374 {
375  Q_Q(QLocalSocket);
376  q->close();
377 }
378 
379 void QLocalSocketPrivate::cancelDelayedConnect()
380 {
381  if (delayConnect) {
382  delayConnect->setEnabled(false);
383  delete delayConnect;
384  delayConnect = 0;
385  connectTimer->stop();
386  delete connectTimer;
387  connectTimer = 0;
388  }
389 }
390 
392 {
393  Q_D(const QLocalSocket);
394  return d->unixSocket.socketDescriptor();
395 }
396 
398 {
399  Q_D(QLocalSocket);
400  return d->unixSocket.readData(data, c);
401 }
402 
404 {
405  Q_D(QLocalSocket);
406  return d->unixSocket.writeData(data, c);
407 }
408 
409 void QLocalSocket::abort()
410 {
411  Q_D(QLocalSocket);
412  d->unixSocket.abort();
413 }
414 
416 {
417  Q_D(const QLocalSocket);
418  return QIODevice::bytesAvailable() + d->unixSocket.bytesAvailable();
419 }
420 
422 {
423  Q_D(const QLocalSocket);
424  return d->unixSocket.bytesToWrite();
425 }
426 
427 bool QLocalSocket::canReadLine() const
428 {
429  Q_D(const QLocalSocket);
430  return QIODevice::canReadLine() || d->unixSocket.canReadLine();
431 }
432 
433 void QLocalSocket::close()
434 {
435  Q_D(QLocalSocket);
436  d->unixSocket.close();
437  d->cancelDelayedConnect();
438  if (d->connectingSocket != -1)
439  ::close(d->connectingSocket);
440  d->connectingSocket = -1;
441  d->connectingName.clear();
442  d->connectingOpenMode = 0;
443  d->serverName.clear();
444  d->fullServerName.clear();
446 }
447 
448 bool QLocalSocket::waitForBytesWritten(int msecs)
449 {
450  Q_D(QLocalSocket);
451  return d->unixSocket.waitForBytesWritten(msecs);
452 }
453 
454 bool QLocalSocket::flush()
455 {
456  Q_D(QLocalSocket);
457  return d->unixSocket.flush();
458 }
459 
461 {
462  Q_D(QLocalSocket);
463  d->unixSocket.disconnectFromHost();
464 }
465 
467 {
468  Q_D(const QLocalSocket);
469  switch (d->unixSocket.error()) {
490  default:
491 #if defined QLOCALSOCKET_DEBUG
492  qWarning() << "QLocalSocket error not handled:" << d->unixSocket.error();
493 #endif
494  break;
495  }
496  return UnknownSocketError;
497 }
498 
499 bool QLocalSocket::isValid() const
500 {
501  Q_D(const QLocalSocket);
502  return d->unixSocket.isValid();
503 }
504 
506 {
507  Q_D(const QLocalSocket);
508  return d->unixSocket.readBufferSize();
509 }
510 
512 {
513  Q_D(QLocalSocket);
514  d->unixSocket.setReadBufferSize(size);
515 }
516 
517 bool QLocalSocket::waitForConnected(int msec)
518 {
519  Q_D(QLocalSocket);
520  if (state() != ConnectingState)
521  return (state() == ConnectedState);
522 
523  fd_set fds;
524  FD_ZERO(&fds);
525  FD_SET(d->connectingSocket, &fds);
526 
527  timeval timeout;
528  timeout.tv_sec = msec / 1000;
529  timeout.tv_usec = (msec % 1000) * 1000;
530 
531  // timeout can not be 0 or else select will return an error.
532  if (0 == msec)
533  timeout.tv_usec = 1000;
534 
535  int result = -1;
536  // on Linux timeout will be updated by select, but _not_ on other systems.
538  timer.start();
539  while (state() == ConnectingState
540  && (-1 == msec || timer.elapsed() < msec)) {
541 #ifdef Q_OS_SYMBIAN
542  // On Symbian, ready-to-write is signaled when non-blocking socket
543  // connect is finised. Is ready-to-read really used on other
544  // UNIX paltforms when using non-blocking AF_UNIX socket?
545  result = ::select(d->connectingSocket + 1, 0, &fds, 0, &timeout);
546 #else
547  result = ::select(d->connectingSocket + 1, &fds, 0, 0, &timeout);
548 #endif
549  if (-1 == result && errno != EINTR) {
550  d->errorOccurred( QLocalSocket::UnknownSocketError,
551  QLatin1String("QLocalSocket::waitForConnected"));
552  break;
553  }
554  if (result > 0)
555  d->_q_connectToSocket();
556  }
557 
558  return (state() == ConnectedState);
559 }
560 
561 bool QLocalSocket::waitForDisconnected(int msecs)
562 {
563  Q_D(QLocalSocket);
564  if (state() == UnconnectedState) {
565  qWarning() << "QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState";
566  return false;
567  }
568  return (d->unixSocket.waitForDisconnected(msecs));
569 }
570 
571 bool QLocalSocket::waitForReadyRead(int msecs)
572 {
573  Q_D(QLocalSocket);
575  return false;
576  return (d->unixSocket.waitForReadyRead(msecs));
577 }
578 
580 
581 #endif
double d
Definition: qnumeric_p.h:62
quintptr socketDescriptor() const
Returns the native socket descriptor of the QLocalSocket object if this is available; otherwise retur...
bool waitForReadyRead(int msecs=30000)
This function blocks until data is available for reading and the QIODevice::readyRead() signal has be...
QIntegerForSizeof< void * >::Unsigned quintptr
Definition: qglobal.h:986
unsigned char c[8]
Definition: qnumeric_p.h:62
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
LocalSocketState
This enum describes the different states in which a socket can be.
Definition: qlocalsocket.h:78
bool waitForConnected(int msecs=30000)
Waits until the socket is connected, up to msecs milliseconds.
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
QIODevice::OpenMode openMode
Definition: qiodevice_p.h:212
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
Definition: qiodevice.cpp:590
QLocalSocket::LocalSocketState state
#define SLOT(a)
Definition: qobjectdefs.h:226
virtual void close()
Reimplemented Function
int select(int, fd_set *, fd_set *, fd_set *, struct timeval *)
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
#define QT_CONNECT_TIMEOUT
EventLoopTimerRef timer
bool waitForDisconnected(int msecs=30000)
Waits until the socket has disconnected, up to msecs milliseconds.
The QString class provides a Unicode character string.
Definition: qstring.h:83
virtual qint64 writeData(const char *, qint64)
Reimplemented Function
QLocalSocket::LocalSocketError error
#define Q_D(Class)
Definition: qglobal.h:2482
The QElapsedTimer class provides a fast way to calculate elapsed times.
Definition: qelapsedtimer.h:53
The QLocalSocket class provides a local socket.
Definition: qlocalsocket.h:58
qint64 elapsed() const
Returns the number of milliseconds since this QElapsedTimer was last started.
qint64 readBufferSize() const
Returns the size of the internal read buffer.
The QSocketNotifier class provides support for monitoring activity on a file descriptor.
#define Q_Q(Class)
Definition: qglobal.h:2483
SocketState
This enum describes the different states in which a socket can be.
#define SIGNAL(a)
Definition: qobjectdefs.h:227
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QIntfbScreen * connected
static int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SOCKLEN_T addrlen)
Definition: qnet_unix_p.h:145
virtual qint64 readData(char *, qint64)
Reimplemented Function
void setReadBufferSize(qint64 size)
Sets the size of QLocalSocket&#39;s internal read buffer to be size bytes.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
const char * name
#define emit
Definition: qobjectdefs.h:76
SocketError
This enum describes the socket errors that can occur.
Q_CORE_EXPORT void qWarning(const char *,...)
bool flush()
This function writes as much as possible from the internal write buffer to the socket, without blocking.
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
void connectToServer(const QString &name, OpenMode openMode=ReadWrite)
Attempts to make a connection to name.
QString errorString
Definition: qiodevice_p.h:213
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
__int64 qint64
Definition: qglobal.h:942
LocalSocketError error() const
Returns the type of error that last occurred.
virtual qint64 bytesToWrite() const
Reimplemented Function
bool isValid() const
Returns true if the socket is valid and ready for use; otherwise returns false.
static QString tempPath()
Returns the absolute path of the system&#39;s temporary directory.
Definition: qdir.cpp:1987
virtual bool canReadLine() const
Reimplemented Function
int fcntl(int, int,...)
void abort()
Aborts the current connection and resets the socket.
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
static int qt_safe_socket(int domain, int type, int protocol, int flags=0)
Definition: qnet_unix_p.h:83
void clear()
Clears the contents of the string and makes it empty.
Definition: qstring.h:723
bool waitForBytesWritten(int msecs=30000)
Reimplemented Function
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
Definition: qiodevice.cpp:752
virtual qint64 bytesAvailable() const
Reimplemented Function
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
virtual bool open(OpenMode mode)
Opens the device and sets its OpenMode to mode.
Definition: qiodevice.cpp:570
virtual bool canReadLine() const
Returns true if a complete line of data can be read from the device; otherwise returns false...
Definition: qiodevice.cpp:1330
The QTimer class provides repetitive and single-shot timers.
Definition: qtimer.h:56
LocalSocketError
The LocalServerError enumeration represents the errors that can occur.
Definition: qlocalsocket.h:64
void start()
Starts this timer.
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
bool setSocketDescriptor(quintptr socketDescriptor, LocalSocketState socketState=ConnectedState, OpenMode openMode=ReadWrite)
void disconnectFromServer()
Attempts to close the socket.
int errno