Qt 4.8
qunixsocket.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 QtGui 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 "qunixsocket_p.h"
43 
44 // #define QUNIXSOCKET_DEBUG 1
45 
46 #include <QtCore/qsocketnotifier.h>
47 #include <QtCore/qqueue.h>
48 #include <QtCore/qdatetime.h>
49 #include "private/qcore_unix_p.h" // overrides QT_OPEN
50 
51 #ifdef QUNIXSOCKET_DEBUG
52 #include <QtCore/qdebug.h>
53 #endif
54 
55 extern "C" {
56 #include <unistd.h>
57 #include <string.h>
58 #include <errno.h>
59 #include <sys/socket.h>
60 #include <sys/un.h>
61 };
62 
63 #define UNIX_PATH_MAX 108 // From unix(7)
64 
65 #ifdef QT_LINUXBASE
66 // LSB doesn't declare ucred
67 struct ucred
68 {
69  pid_t pid; /* PID of sending process. */
70  uid_t uid; /* UID of sending process. */
71  gid_t gid; /* GID of sending process. */
72 };
73 
74 // LSB doesn't define the ones below
75 #ifndef SO_PASSCRED
76 # define SO_PASSCRED 16
77 #endif
78 #ifndef SCM_CREDENTIALS
79 # define SCM_CREDENTIALS 0x02
80 #endif
81 #ifndef MSG_DONTWAIT
82 # define MSG_DONTWAIT 0x40
83 #endif
84 #ifndef MSG_NOSIGNAL
85 # define MSG_NOSIGNAL 0x4000
86 #endif
87 
88 #endif // QT_LINUXBASE
89 
91 
93 // class QUnixSocketRights
95 
133 {
135 #ifdef QUNIXSOCKET_DEBUG
136  int closerv =
137 #endif
138  QT_CLOSE(fd);
139 #ifdef QUNIXSOCKET_DEBUG
140  if(0 != closerv) {
141  qDebug() << "QUnixSocketRightsPrivate: Unable to close managed"
142  " file descriptor (" << ::strerror(errno) << ')';
143  }
144 #endif
145  }
146 
147  int fd;
148 };
149 
164 {
165  d = new QUnixSocketRightsPrivate();
166  if(-1 == fd) {
167  d->fd = -1;
168  } else {
169  d->fd = qt_safe_dup(fd);
170 #ifdef QUNIXSOCKET_DEBUG
171  if(-1 == d->fd) {
172  qDebug() << "QUnixSocketRights: Unable to duplicate fd "
173  << fd << " (" << ::strerror(errno) << ')';
174  }
175 #endif
176  }
177 }
178 
189 {
190  Q_ASSERT(-1 != fd);
191  d = new QUnixSocketRightsPrivate();
192  d->fd = fd;
193 }
194 
199 {
200 }
201 
207 {
208  d = other.d;
209  return *this;
210 }
211 
216 : d(other.d)
217 {
218 }
219 
227 {
228  return d->fd != -1;
229 }
230 
239 {
240  if(-1 == d->fd) return -1;
241 
242  int rv = qt_safe_dup(d->fd);
243 
244 #ifdef QUNIXSOCKET_DEBUG
245  if(-1 == rv)
246  qDebug() << "QUnixSocketRights: Unable to duplicate managed file "
247  "descriptor (" << ::strerror(errno) << ')';
248 #endif
249 
250  return rv;
251 }
252 
267 {
268  return d->fd;
269 }
270 
272 // class QUnixSocketMessage
275 {
277  : state(Default), vec(0), iovecLen(0), dataSize(0) {}
279  : bytes(b), state(Default), vec(0), iovecLen(0), dataSize(0) {}
281  const QList<QUnixSocketRights> & r)
282  : bytes(b), rights(r), state(Default), vec(0), iovecLen(0), dataSize(0) {}
283 
284  int size() const { return vec ? dataSize : bytes.size(); }
285  void removeBytes( unsigned int );
286 
289 
291  Default = 0x00,
292  Truncated = 0x01,
293  Credential = 0x02
294  };
296 
297  pid_t pid;
298  gid_t gid;
299  uid_t uid;
300 
301  ::iovec *vec;
302  int iovecLen; // number of vectors in array
303  int dataSize; // total size of vectors = payload
304 };
305 
310 void QUnixSocketMessagePrivate::removeBytes( unsigned int bytesToDequeue )
311 {
312  if ( vec )
313  {
314  ::iovec *vecPtr = vec;
315  if ( bytesToDequeue > (unsigned int)dataSize ) bytesToDequeue = dataSize;
316  while ( bytesToDequeue > 0 && iovecLen > 0 )
317  {
318  if ( vecPtr->iov_len > bytesToDequeue )
319  {
320  // dequeue the bytes by taking them off the front of the
321  // current vector. since we don't own the iovec, its okay
322  // to "leak" this away by pointing past it
323  char **base = reinterpret_cast<char**>(&(vecPtr->iov_base));
324  *base += bytesToDequeue;
325  vecPtr->iov_len -= bytesToDequeue;
326  bytesToDequeue = 0;
327  }
328  else
329  {
330  // dequeue bytes by skipping a whole vector. again, its ok
331  // to lose the pointers to this data
332  bytesToDequeue -= vecPtr->iov_len;
333  iovecLen--;
334  vecPtr++;
335  }
336  }
337  dataSize -= bytesToDequeue;
338  if ( iovecLen == 0 ) vec = 0;
339  }
340  else
341  {
342  bytes.remove(0, bytesToDequeue );
343  }
344 }
345 
346 
408 {
409 }
410 
416 : d(new QUnixSocketMessagePrivate(bytes))
417 {
418 }
419 
430 : d(new QUnixSocketMessagePrivate(bytes, rights))
431 {
432 }
433 
438 : d(other.d)
439 {
440 }
441 
458 QUnixSocketMessage::QUnixSocketMessage(const ::iovec* data, int vecLen )
460 {
461  for ( int v = 0; v < vecLen; v++ )
462  d->dataSize += data[v].iov_len;
463  d->vec = const_cast<iovec*>(data);
464  d->iovecLen = vecLen;
465 }
466 
471 {
472  d = other.d;
473  return *this;
474 }
475 
480 {
481 }
482 
489 {
490  d.detach();
491  d->bytes = bytes;
492 }
493 
503 {
504  d.detach();
505  d->rights = rights;
506 }
507 
514 {
515  return d->rights;
516 }
517 
528 {
530 }
531 
538 {
539  return d->bytes;
540 }
541 
548 {
550  return d->pid;
551  else
552  return ::getpid();
553 }
554 
561 {
563  return d->uid;
564  else
565  return ::geteuid();
566 }
567 
574 {
576  return d->gid;
577  else
578  return ::getegid();
579 }
580 
589 {
592  d->uid = ::geteuid();
593  d->gid = ::getegid();
594  }
595  d->pid = pid;
596 }
597 
606 {
609  d->pid = ::getpid();
610  d->gid = ::getegid();
611  }
612  d->uid = uid;
613 }
614 
623 {
626  d->pid = ::getpid();
627  d->uid = ::geteuid();
628  }
629  d->gid = gid;
630 }
631 
638 {
639  return d->rights.isEmpty() || !d->bytes.isEmpty();
640 }
641 
643 // class QUnixSocket
645 #define QUNIXSOCKET_DEFAULT_READBUFFER 1024
646 #define QUNIXSOCKET_DEFAULT_ANCILLARYBUFFER 0
647 
772 /*
773  \fn QUnixSocket::bytesWritten(qint64 bytes)
774 
775  This signal is emitted every time a payload of data has been written to the
776  connection. The \a bytes argument is set to the number of bytes that were
777  written in this payload.
778 
779  \sa QUnixSocket::readyRead()
780 */
781 
782 /*
783  \fn QUnixSocket::readyRead()
784 
785  This signal is emitted once every time new data is available for reading from
786  the connection. It will only be emitted again once new data is available.
787 
788  \sa QUnixSocket::bytesWritten()
789 */
790 
801 class QUnixSocketPrivate : public QObject {
802 Q_OBJECT
803 public:
805  : me(_me), fd(-1), readNotifier(0), writeNotifier(0),
806  state(QUnixSocket::UnconnectedState), error(QUnixSocket::NoError),
807  writeQueueBytes(0), messageValid(false), dataBuffer(0),
808  dataBufferLength(0), dataBufferCapacity(0), ancillaryBuffer(0),
809  ancillaryBufferCount(0), closingTimer(0) {
810  QObject::connect(this, SIGNAL(readyRead()), me, SIGNAL(readyRead()));
811  QObject::connect(this, SIGNAL(bytesWritten(qint64)),
812  me, SIGNAL(bytesWritten(qint64)));
813  }
815  {
816  if(dataBuffer)
817  delete [] dataBuffer;
818  if(ancillaryBuffer)
819  delete [] ancillaryBuffer;
820  }
821 
822  enum { CausedAbort = 0x70000000 };
823 
825 
826  int fd;
827 
830 
833 
835  unsigned int writeQueueBytes;
836 
838  ::msghdr message;
839  inline void flushAncillary()
840  {
841  if(!messageValid) return;
842  ::cmsghdr * h = (::cmsghdr *)CMSG_FIRSTHDR(&(message));
843  while(h) {
844 
845  if(SCM_RIGHTS == h->cmsg_type) {
846  int * fds = (int *)CMSG_DATA(h);
847  int numFds = (h->cmsg_len - CMSG_LEN(0)) / sizeof(int);
848 
849  for(int ii = 0; ii < numFds; ++ii)
850  QT_CLOSE(fds[ii]);
851  }
852 
853  h = (::cmsghdr *)CMSG_NXTHDR(&(message), h);
854  }
855 
856  messageValid = false;
857  }
858 
859 
860  char * dataBuffer;
861  unsigned int dataBufferLength;
862  unsigned int dataBufferCapacity;
863 
865  inline unsigned int ancillaryBufferCapacity()
866  {
867  return CMSG_SPACE(sizeof(::ucred)) + CMSG_SPACE(sizeof(int) * ancillaryBufferCount);
868  }
869  unsigned int ancillaryBufferCount;
870 
872 
874 
875  virtual void timerEvent(QTimerEvent *)
876  {
877  me->abort();
878  killTimer(closingTimer);
879  closingTimer = 0;
880  }
881 signals:
882  void readyRead();
883  void bytesWritten(qint64);
884 
885 public slots:
886  void readActivated();
887  qint64 writeActivated();
888 };
889 
899 : QIODevice(parent), d(new QUnixSocketPrivate(this))
900 {
904 }
905 
915  QObject * parent)
916 : QIODevice(parent), d(new QUnixSocketPrivate(this))
917 {
918  Q_ASSERT(readBufferSize > 0 && rightsBufferSize >= 0);
919 
921  setReadBufferSize(readBufferSize);
922  setRightsBufferSize(rightsBufferSize);
923 }
924 
929 {
930  abort();
931  delete d;
932 }
933 
947 {
948  int _true;
949  int crv;
950 #ifdef QUNIXSOCKET_DEBUG
951  qDebug() << "QUnixSocket: Connect requested to '"
952  << path << '\'';
953 #endif
954 
955  abort(); // Reset any existing connection
956 
957  if(UnconnectedState != d->state) // abort() caused a signal and someone messed
958  // with us. We'll assume they know what
959  // they're doing and bail. Alternative is to
960  // have a special "Connecting" state
961  return false;
962 
963 
964  if(path.isEmpty() || path.size() > UNIX_PATH_MAX) {
965  d->error = InvalidPath;
966  return false;
967  }
968 
969  // Create the socket
970  d->fd = ::socket(PF_UNIX, SOCK_STREAM, 0);
971  if(-1 == d->fd) {
972 #ifdef QUNIXSOCKET_DEBUG
973  qDebug() << "QUnixSocket: Unable to create socket ("
974  << strerror(errno) << ')';
975 #endif
976  d->error = ResourceError;
977  goto connect_error;
978  }
979 
980  // Set socket options
981  _true = 1;
982  crv = ::setsockopt(d->fd, SOL_SOCKET, SO_PASSCRED, (void *)&_true,
983  sizeof(int));
984  if(-1 == crv) {
985 #ifdef QUNIXSOCKET_DEBUG
986  qDebug() << "QUnixSocket: Unable to configure socket ("
987  << ::strerror(errno) << ')';
988 #endif
989  d->error = ResourceError;
990 
991  goto connect_error;
992  }
993 
994  // Construct our unix address
995  struct ::sockaddr_un addr;
996  addr.sun_family = AF_UNIX;
997  ::memcpy(addr.sun_path, path.data(), path.size());
998  if(path.size() < UNIX_PATH_MAX)
999  addr.sun_path[path.size()] = '\0';
1000 
1001  // Attempt the connect
1002  crv = ::connect(d->fd, (sockaddr *)&addr, sizeof(sockaddr_un));
1003  if(-1 == crv) {
1004 #ifdef QUNIXSOCKET_DEBUG
1005  qDebug() << "QUnixSocket: Unable to connect ("
1006  << ::strerror(errno) << ')';
1007 #endif
1008  if(ECONNREFUSED == errno)
1010  else if(ENOENT == errno)
1011  d->error = NonexistentPath;
1012  else
1013  d->error = UnknownError;
1014 
1015  goto connect_error;
1016  }
1017 
1018  // We're connected!
1019  d->address = path;
1020  d->state = ConnectedState;
1023  QObject::connect(d->readNotifier, SIGNAL(activated(int)),
1024  d, SLOT(readActivated()));
1025  QObject::connect(d->writeNotifier, SIGNAL(activated(int)),
1026  d, SLOT(writeActivated()));
1027  d->readNotifier->setEnabled(true);
1028  d->writeNotifier->setEnabled(false);
1031 
1032 #ifdef QUNIXSOCKET_DEBUG
1033  qDebug() << "QUnixSocket: Connected to " << path;
1034 #endif
1035  return true;
1036 
1037 connect_error: // Cleanup failed connection
1038  if(-1 != d->fd) {
1039 #ifdef QUNIXSOCKET_DEBUG
1040  int closerv =
1041 #endif
1042  QT_CLOSE(d->fd);
1043 #ifdef QUNIXSOCKET_DEBUG
1044  if(0 != closerv) {
1045  qDebug() << "QUnixSocket: Unable to close file descriptor after "
1046  "failed connect (" << ::strerror(errno) << ')';
1047  }
1048 #endif
1049  }
1050  d->fd = -1;
1051  return false;
1052 }
1053 
1068 {
1069  abort();
1070 
1071  if(UnconnectedState != state()) // See QUnixSocket::connect()
1072  return false;
1073 
1074  // Attempt to set the socket options
1075  if(-1 == socketDescriptor) {
1076 #ifdef QUNIXSOCKET_DEBUG
1077  qDebug() << "QUnixSocket: User provided socket is invalid";
1078 #endif
1079  d->error = ResourceError;
1080  return false;
1081  }
1082 
1083  // Set socket options
1084  int _true = 1;
1085  int crv = ::setsockopt(socketDescriptor, SOL_SOCKET,
1086  SO_PASSCRED, (void *)&_true, sizeof(int));
1087  if(-1 == crv) {
1088 #ifdef QUNIXSOCKET_DEBUG
1089  qDebug() << "QUnixSocket: Unable to configure client provided socket ("
1090  << ::strerror(errno) << ')';
1091 #endif
1092  d->error = ResourceError;
1093 
1094  return false;
1095  }
1096 
1097  d->fd = socketDescriptor;
1098  d->state = ConnectedState;
1099  d->address = QByteArray();
1103  QObject::connect(d->readNotifier, SIGNAL(activated(int)),
1104  d, SLOT(readActivated()));
1105  QObject::connect(d->writeNotifier, SIGNAL(activated(int)),
1106  d, SLOT(writeActivated()));
1107  d->readNotifier->setEnabled(true);
1108  d->writeNotifier->setEnabled(false);
1110 
1111  return true;
1112 }
1113 
1121 {
1122  return d->fd;
1123 }
1124 
1134 {
1136 
1137  // We want to be able to use QUnixSocket::abort() to cleanup our state but
1138  // also preserve the error message that caused the abort. It is not
1139  // possible to reorder code to do this:
1140  // abort();
1141  // d->error = SomeError
1142  // as QUnixSocket::abort() might emit a signal and we need the error to be
1143  // set within that signal. So, if we want an error message to be preserved
1144  // across a *single* call to abort(), we set the
1145  // QUnixSocketPrivate::CausedAbort flag in the error.
1149  else
1150  d->error = NoError;
1151 
1152  if( UnconnectedState == d->state) return;
1153 
1154 #ifdef QUNIXSOCKET_DEBUG
1155  int closerv =
1156 #endif
1157  ::close(d->fd);
1158 #ifdef QUNIXSOCKET_DEBUG
1159  if(0 != closerv) {
1160  qDebug() << "QUnixSocket: Unable to close socket during abort ("
1161  << strerror(errno) << ')';
1162  }
1163 #endif
1164 
1165  // Reset variables
1166  d->fd = -1;
1168  d->dataBufferLength = 0;
1169  d->flushAncillary();
1170  d->address = QByteArray();
1171  if(d->readNotifier) {
1172  d->readNotifier->setEnabled(false);
1174  }
1175  if(d->writeNotifier) {
1176  d->writeNotifier->setEnabled(false);
1178  }
1179  d->readNotifier = 0;
1180  d->writeNotifier = 0;
1181  d->writeQueue.clear();
1182  d->writeQueueBytes = 0;
1183  if(d->closingTimer) {
1185  }
1186  d->closingTimer = 0;
1188 }
1189 
1202 {
1203  if(ConnectedState != state()) return;
1204 
1205  d->state = ClosingState;
1206  if(d->writeQueue.isEmpty()) {
1207  d->closingTimer = d->startTimer(0); // Start a timer to "fake"
1208  // completing writes
1209  }
1211 }
1212 
1218 // Note! docs partially copied from QAbstractSocket::flush()
1220 {
1221  // This needs to have the same semantics as QAbstractSocket, if it is to
1222  // be used interchangeably with that class.
1223  if (d->writeQueue.isEmpty())
1224  return false;
1225 
1226  d->writeActivated();
1227  return true;
1228 }
1229 
1237 {
1238  return (QUnixSocket::SocketError)
1239  (d->error & ~QUnixSocketPrivate::CausedAbort);
1240 }
1241 
1246 {
1247  return d->state;
1248 }
1249 
1259 {
1260  return d->address;
1261 }
1262 
1268 {
1270 }
1271 
1276 {
1277  return d->writeQueueBytes;
1278 }
1279 
1293 {
1294  return d->dataBufferCapacity;
1295 }
1296 
1309 {
1310  Q_ASSERT(size > 0);
1311  if(size == d->dataBufferCapacity || d->dataBufferLength) return;
1312  if(d->dataBuffer) delete [] d->dataBuffer;
1313  d->dataBuffer = new char[size];
1315 }
1316 
1335 {
1336  return d->ancillaryBufferCount;
1337 }
1338 
1351 {
1352  Q_ASSERT(size >= 0);
1353 
1354  if((size == d->ancillaryBufferCount || d->dataBufferLength) &&
1355  d->ancillaryBuffer)
1356  return;
1357 
1358  qint64 byteSize = CMSG_SPACE(sizeof(::ucred)) +
1359  CMSG_SPACE(size * sizeof(int));
1360 
1361  if(d->ancillaryBuffer) delete [] d->ancillaryBuffer;
1362  d->ancillaryBuffer = new char[byteSize];
1364 }
1365 
1389 {
1390  if(ConnectedState != state() || !socketdata.isValid()) return -1;
1391  if(socketdata.d->size() == 0) return 0;
1392 
1393  d->writeQueue.enqueue(socketdata);
1394  d->writeQueueBytes += socketdata.d->size();
1395  d->writeNotifier->setEnabled(true);
1396 
1397  return socketdata.d->size();
1398 }
1399 
1410 {
1412  if(!d->dataBufferLength)
1413  return data;
1414 
1416 
1417  // Bytes are easy
1419 
1420  // Extract ancillary data
1422 
1423  ::cmsghdr * h = (::cmsghdr *)CMSG_FIRSTHDR(&(d->message));
1424  while(h) {
1425 
1426  if(SCM_CREDENTIALS == h->cmsg_type) {
1427  ::ucred * cred = (::ucred *)CMSG_DATA(h);
1428 #ifdef QUNIXSOCKET_DEBUG
1429  qDebug( "Credentials recd: pid %lu - gid %lu - uid %lu",
1430  cred->pid, cred->gid, cred->uid );
1431 #endif
1432  data.d->pid = cred->pid;
1433  data.d->gid = cred->gid;
1434  data.d->uid = cred->uid;
1435 
1436  } else if(SCM_RIGHTS == h->cmsg_type) {
1437 
1438  int * fds = (int *)CMSG_DATA(h);
1439  int numFds = (h->cmsg_len - CMSG_LEN(0)) / sizeof(int);
1440 
1441  for(int ii = 0; ii < numFds; ++ii) {
1442  QUnixSocketRights qusr(fds[ii], 0);
1443  a.append(qusr);
1444  }
1445 
1446  } else {
1447 
1448 #ifdef QUNIXSOCKET_DEBUG
1449  qFatal("QUnixSocket: Unknown ancillary data type (%d) received.",
1450  h->cmsg_type);
1451 #endif
1452 
1453  }
1454 
1455  h = (::cmsghdr *)CMSG_NXTHDR(&(d->message), h);
1456  }
1457 
1458  if(d->message.msg_flags & MSG_CTRUNC) {
1461  }
1462 
1463  if(!a.isEmpty())
1464  data.d->rights = a;
1465 
1466  d->dataBufferLength = 0;
1467  d->messageValid = false;
1468  d->readNotifier->setEnabled(true);
1469 
1470  return data;
1471 }
1472 
1475 {
1476  return true;
1477 }
1478 
1481 {
1482  if(UnconnectedState == d->state)
1483  return false;
1484 
1485  if(d->messageValid) {
1486  return true;
1487  }
1488 
1489  Q_ASSERT(-1 != d->fd);
1490 
1491  int timeout = msecs;
1492  struct timeval tv;
1493  struct timeval *ptrTv = 0;
1494  QTime stopWatch;
1495 
1496  stopWatch.start();
1497 
1498  do
1499  {
1500  fd_set readset;
1501 
1502  FD_ZERO(&readset);
1503  FD_SET(d->fd, &readset);
1504 
1505  if(-1 != msecs) {
1506  tv.tv_sec = timeout / 1000;
1507  tv.tv_usec = (timeout % 1000) * 1000;
1508  ptrTv = &tv;
1509  }
1510 
1511  int rv = ::select(d->fd + 1, &readset, 0, 0, ptrTv);
1512  switch(rv) {
1513  case 0:
1514  // timeout
1515  return false;
1516  case 1:
1517  // ok
1518  d->readActivated();
1519  return true;
1520  default:
1521  if (errno != EINTR)
1522  abort(); // error
1523  break;
1524  }
1525 
1526  timeout = msecs - stopWatch.elapsed();
1527  }
1528  while (timeout > 0);
1529 
1530  return false;
1531 }
1532 
1534 {
1535  if(UnconnectedState == d->state)
1536  return false;
1537 
1538  Q_ASSERT(-1 != d->fd);
1539 
1540  if ( d->writeQueue.isEmpty() )
1541  return true;
1542 
1543  QTime stopWatch;
1544  stopWatch.start();
1545 
1546  while ( true )
1547  {
1548  fd_set fdwrite;
1549  FD_ZERO(&fdwrite);
1550  FD_SET(d->fd, &fdwrite);
1551  int timeout = msecs < 0 ? 0 : msecs - stopWatch.elapsed();
1552  struct timeval tv;
1553  struct timeval *ptrTv = 0;
1554  if ( -1 != msecs )
1555  {
1556  tv.tv_sec = timeout / 1000;
1557  tv.tv_usec = (timeout % 1000) * 1000;
1558  ptrTv = &tv;
1559  }
1560 
1561  int rv = ::select(d->fd + 1, 0, &fdwrite, 0, ptrTv);
1562  switch ( rv )
1563  {
1564  case 0:
1565  // timeout
1566  return false;
1567  case 1:
1568  {
1569  // ok to write
1571  if (bytesWritten == 0) {
1572  // We need to retry
1573  int delay = 1;
1574  do {
1575  if (-1 != msecs) {
1576  timeout = msecs - stopWatch.elapsed();
1577  if (timeout <= 0) {
1578  // We have exceeded our allotted time
1579  return false;
1580  } else {
1581  if (delay > timeout)
1582  delay = timeout;
1583  }
1584  }
1585 
1586  // Pause before we make another attempt to send
1587  ::usleep(delay * 1000);
1588  if (delay < 1024)
1589  delay *= 2;
1590 
1591  bytesWritten = d->writeActivated();
1592  } while (bytesWritten == 0);
1593  }
1594  return (bytesWritten != -1);
1595  }
1596  default:
1597  // error - or an uncaught signal!!!!!!!!!
1598  if ( rv == EINTR )
1599  continue;
1600  abort();
1601  return false;
1602  }
1603  }
1604  return false; // fix warnings
1605 }
1606 
1609 {
1610  for(unsigned int ii = 0; ii < d->dataBufferLength; ++ii)
1611  if(d->dataBuffer[ii] == '\n') return true;
1612  return false;
1613 }
1614 
1617 {
1618  Q_ASSERT(data);
1619  if(0 >= maxSize) return 0;
1620  if(!d->dataBufferLength) return 0;
1621 
1622  // Read data
1623  unsigned int size = d->dataBufferLength>maxSize?maxSize:d->dataBufferLength;
1624  memcpy(data, d->dataBuffer, size);
1625  if(size == d->dataBufferLength) {
1626  d->dataBufferLength = 0;
1627  } else {
1628  memmove(d->dataBuffer, d->dataBuffer + size, d->dataBufferLength - size);
1629  d->dataBufferLength -= size;
1630  }
1631 
1632 
1633  // Flush ancillary
1634  d->flushAncillary();
1635 
1636  if(0 == d->dataBufferLength)
1637  d->readNotifier->setEnabled(true);
1638 
1639  return size;
1640 }
1641 
1643 qint64 QUnixSocket::writeData (const char * data, qint64 maxSize)
1644 {
1645  return write(QUnixSocketMessage(QByteArray(data, maxSize)));
1646 }
1647 
1649 {
1650  writeNotifier->setEnabled(false);
1651 
1652  QUnixSocketMessage & m = writeQueue.head();
1653  const QList<QUnixSocketRights> & a = m.rights();
1654 
1655  //
1656  // Construct the message
1657  //
1658  ::iovec vec;
1659  if ( !m.d->vec ) // message does not already have an iovec
1660  {
1661  vec.iov_base = (void *)m.bytes().constData();
1662  vec.iov_len = m.bytes().size();
1663  }
1664 
1665  // Allocate the control buffer
1666  ::msghdr sendmessage;
1667  ::bzero(&sendmessage, sizeof(::msghdr));
1668  if ( m.d->vec )
1669  {
1670  sendmessage.msg_iov = m.d->vec;
1671  sendmessage.msg_iovlen = m.d->iovecLen;
1672  }
1673  else
1674  {
1675  sendmessage.msg_iov = &vec;
1676  sendmessage.msg_iovlen = 1;
1677  }
1678  unsigned int required = CMSG_SPACE(sizeof(::ucred)) +
1679  a.size() * CMSG_SPACE(sizeof(int));
1680  sendmessage.msg_control = new char[required];
1681  ::bzero(sendmessage.msg_control, required);
1682  sendmessage.msg_controllen = required;
1683 
1684  // Create ancillary buffer
1685  ::cmsghdr * h = CMSG_FIRSTHDR(&sendmessage);
1686 
1688  h->cmsg_len = CMSG_LEN(sizeof(::ucred));
1689  h->cmsg_level = SOL_SOCKET;
1690  h->cmsg_type = SCM_CREDENTIALS;
1691  ((::ucred *)CMSG_DATA(h))->pid = m.d->pid;
1692  ((::ucred *)CMSG_DATA(h))->gid = m.d->gid;
1693  ((::ucred *)CMSG_DATA(h))->uid = m.d->uid;
1694  h = CMSG_NXTHDR(&sendmessage, h);
1695  } else {
1696  sendmessage.msg_controllen -= CMSG_SPACE(sizeof(::ucred));
1697  }
1698 
1699  for(int ii = 0; ii < a.count(); ++ii) {
1700  const QUnixSocketRights & r = a.at(ii);
1701 
1702  if(r.isValid()) {
1703  h->cmsg_len = CMSG_LEN(sizeof(int));
1704  h->cmsg_level = SOL_SOCKET;
1705  h->cmsg_type = SCM_RIGHTS;
1706  *((int *)CMSG_DATA(h)) = r.peekFd();
1707  h = CMSG_NXTHDR(&sendmessage, h);
1708  } else {
1709  sendmessage.msg_controllen -= CMSG_SPACE(sizeof(int));
1710  }
1711  }
1712 
1713 #ifdef QUNIXSOCKET_DEBUG
1714  qDebug() << "QUnixSocket: Transmitting message (length" << m.d->size() << ')';
1715 #endif
1716  ::ssize_t s = ::sendmsg(fd, &sendmessage, MSG_DONTWAIT | MSG_NOSIGNAL);
1717 #ifdef QUNIXSOCKET_DEBUG
1718  qDebug() << "QUnixSocket: Transmitted message (" << s << ')';
1719 #endif
1720 
1721  if(-1 == s) {
1722  if(EAGAIN == errno || EWOULDBLOCK == errno || EINTR == errno) {
1723  writeNotifier->setEnabled(true);
1724  } else if(EPIPE == errno) {
1725 #ifdef QUNIXSOCKET_DEBUG
1726  qDebug() << "QUnixSocket: Remote side disconnected during transmit "
1727  "(" << ::strerror(errno) << ')';
1728 #endif
1729  me->abort();
1730  } else {
1731 #ifdef QUNIXSOCKET_DEBUG
1732  qDebug() << "QUnixSocket: Unable to transmit data ("
1733  << ::strerror(errno) << ')';
1734 #endif
1736  CausedAbort);
1737  me->abort();
1738  }
1739  } else if(s != m.d->size()) {
1740 
1741  // A partial transmission
1742  writeNotifier->setEnabled(true);
1743  delete [] (char *)sendmessage.msg_control;
1745  m.d->removeBytes( s );
1746  writeQueueBytes -= s;
1747  emit bytesWritten(s);
1748  return s;
1749 
1750  } else {
1751 
1752  // Success!
1753  writeQueue.dequeue();
1754  Q_ASSERT(writeQueueBytes >= (unsigned)s);
1755  writeQueueBytes -= s;
1756  emit bytesWritten(s);
1757 
1758  }
1759 
1760  delete [] (char *)sendmessage.msg_control;
1761  if(-1 != s && !writeQueue.isEmpty())
1762  return writeActivated();
1763  else if(QUnixSocket::ClosingState == me->state() && writeQueue.isEmpty())
1764  me->abort();
1765 
1766  if((-1 == s) && (EAGAIN == errno || EWOULDBLOCK == errno || EINTR == errno))
1767  // Return zero bytes written to indicate retry may be required
1768  return 0;
1769  else
1770  return s;
1771 }
1772 
1774 {
1775 #ifdef QUNIXSOCKET_DEBUG
1776  qDebug() << "QUnixSocket: readActivated";
1777 #endif
1778  readNotifier->setEnabled(false);
1779 
1780  ::iovec vec;
1781  vec.iov_base = dataBuffer;
1782  vec.iov_len = dataBufferCapacity;
1783 
1784  bzero(&message, sizeof(::msghdr));
1785  message.msg_iov = &vec;
1786  message.msg_iovlen = 1;
1787  message.msg_controllen = ancillaryBufferCapacity();
1788  message.msg_control = ancillaryBuffer;
1789 
1790  int flags = 0;
1791 #ifdef MSG_CMSG_CLOEXEC
1792  flags = MSG_CMSG_CLOEXEC;
1793 #endif
1794 
1795  int recvrv = ::recvmsg(fd, &message, flags);
1796 #ifdef QUNIXSOCKET_DEBUG
1797  qDebug() << "QUnixSocket: Received message (" << recvrv << ')';
1798 #endif
1799  if(-1 == recvrv) {
1800 #ifdef QUNIXSOCKET_DEBUG
1801  qDebug() << "QUnixSocket: Unable to receive data ("
1802  << ::strerror(errno) << ')';
1803 #endif
1805  CausedAbort);
1806  me->abort();
1807  } else if(0 == recvrv) {
1808  me->abort();
1809  } else {
1810  Q_ASSERT(recvrv);
1811  Q_ASSERT((unsigned)recvrv <= dataBufferCapacity);
1812  dataBufferLength = recvrv;
1813  messageValid = true;
1814 
1815 #ifdef QUNIXSOCKET_DEBUG
1816  qDebug() << "QUnixSocket: readyRead() " << dataBufferLength;
1817 #endif
1818  emit readyRead();
1819  }
1820 }
1821 
1823 
1824 #include "qunixsocket.moc"
unsigned int ancillaryBufferCount
int startTimer(int interval)
Starts a timer and returns a timer identifier, or returns zero if it could not start a timer...
Definition: qobject.cpp:1623
double d
Definition: qnumeric_p.h:62
void abort()
Abort the connection.
AncillaryDataState state
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
Definition: qiodevice.cpp:642
qint64 write(const char *data, qint64 maxSize)
gid_t groupId() const
Returns the group id credential associated with this message.
QSocketNotifier * readNotifier
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QUnixSocketMessage read()
Return the next available message, or an empty message if none is available.
The QUnixSocket class provides a Unix domain socket.
void setOpenMode(OpenMode openMode)
Sets the OpenMode of the device to openMode.
Definition: qiodevice.cpp:477
QUnixSocket::SocketError error
virtual bool isSequential() const
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
QUnixSocketPrivate(QUnixSocket *_me)
void start()
Sets this time to the current time.
Definition: qdatetime.cpp:2070
QSharedDataPointer< QUnixSocketRightsPrivate > d
Definition: qunixsocket_p.h:89
void detach()
If the shared data object&#39;s reference count is greater than 1, this function creates a deep copy of t...
Definition: qshareddata.h:75
void setProcessId(pid_t)
Set the process id credential associated with this message to pid.
#define error(msg)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
bool rightsWereTruncated() const
Returns true if the rights portion of the message was truncated on reception due to insufficient buff...
#define SLOT(a)
Definition: qobjectdefs.h:226
QUnixSocketPrivate * d
int select(int, fd_set *, fd_set *, fd_set *, struct timeval *)
virtual ~QUnixSocketRightsPrivate()
QUnixSocket * me
void close()
Close the connection.
void removeBytes(unsigned int)
SocketState
The SocketState enumeration represents the connection state of a QUnixSocket instance.
long ASN1_INTEGER_get ASN1_INTEGER * a
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
bool isValid() const
Returns true if this QUnixSocketRights instance is managing a valid file descriptor.
void bytesWritten(qint64 bytes)
This signal is emitted every time a payload of data has been written to the device.
qint64 readBufferSize() const
Returns the size of the read buffer in bytes.
QUnixSocketRights(int)
Create a new QUnixSocketRights instance containing the file descriptor fd.
QUnixSocket(QObject *=0)
Construct a QUnixSocket instance, with parent.
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
void setReadBufferSize(qint64 size)
Sets the size of the socket&#39;s read buffer in bytes.
bool flush()
This function writes as much as possible from the internal write buffer to the underlying socket...
static const uint base
Definition: qurl.cpp:268
virtual bool waitForBytesWritten(int msec=300)
For buffered devices, this function waits until a payload of buffered written data has been written t...
The QUnixSocketRights class encapsulates QUnixSocket rights data.
Definition: qunixsocket_p.h:73
QQueue< QUnixSocketMessage > writeQueue
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
The QSocketNotifier class provides support for monitoring activity on a file descriptor.
unsigned int dataBufferLength
static const uint Default
Definition: qsplitter_p.h:61
QUnixSocketMessagePrivate(const QByteArray &b)
Q_CORE_EXPORT void qDebug(const char *,...)
void setGroupId(gid_t)
Set the group id credential associated with this message to gid.
QUnixSocket::SocketState state
#define SIGNAL(a)
Definition: qobjectdefs.h:227
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
The QTime class provides clock time functions.
Definition: qdatetime.h:148
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
const QList< QUnixSocketRights > & rights() const
Return the rights portion of the message.
QList< QUnixSocketRights > rights
int socketDescriptor() const
Returns the socket descriptor currently in use.
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
SocketState state() const
Returns the connection state of this instance.
int peekFd() const
Returns the file descriptor contained in this object.
virtual qint64 writeData(const char *data, qint64 maxSize)
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
bool canReadLine() const
static const char * data(const QByteArray &arr)
virtual qint64 readData(char *data, qint64 maxSize)
SocketError
The SocketError enumeration represents the various errors that can occur on a Unix domain socket...
SocketError error() const
Returns the last error to have occurred on this object.
qint64 bytesAvailable() const
Returns the number of bytes available for immediate retrieval through a call to QUnixSocket::read() ...
void clear()
Removes all items from the list.
Definition: qlist.h:764
__int64 qint64
Definition: qglobal.h:942
QUnixSocketMessage & operator=(const QUnixSocketMessage &)
Assign the contents of other to this object.
unsigned int ancillaryBufferCapacity()
#define Q_OBJECT
Definition: qobjectdefs.h:157
#define QUNIXSOCKET_DEFAULT_READBUFFER
unsigned int writeQueueBytes
void setRights(const QList< QUnixSocketRights > &)
Set the rights portion of the message to rights.
QSharedDataPointer< QUnixSocketMessagePrivate > d
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
void setRightsBufferSize(qint64 size)
Sets the size of the socket&#39;s rights buffer in rights entries.
uid_t userId() const
Returns the user id credential associated with this message.
int elapsed() const
Returns the number of milliseconds that have elapsed since the last time start() or restart() was cal...
Definition: qdatetime.cpp:2123
void enqueue(const T &t)
Adds value t to the tail of the queue.
Definition: qqueue.h:60
Q_CORE_EXPORT void qFatal(const char *,...)
qint64 bytesToWrite() const
Returns the number of enqueued bytes still to be written to the socket.
void setUserId(uid_t)
Set the user id credential associated with this message to uid.
The QSharedData class is a base class for shared data objects.
Definition: qshareddata.h:56
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:341
void stateChanged(SocketState socketState)
This signal is emitted each time the socket changes connection state.
pid_t processId() const
Returns the process id credential associated with this message.
virtual bool waitForReadyRead(int msec=300)
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
Definition: qiodevice.cpp:752
void setEnabled(bool)
If enable is true, the notifier is enabled; otherwise the notifier is disabled.
void setBytes(const QByteArray &)
Set the data portion of the message to bytes.
~QUnixSocketMessage()
Destroy this instance.
qint64 rightsBufferSize() const
Returns the size of the rights buffer in rights entries.
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
bool isValid() const
Return true if this message is valid.
QUnixSocketRights & operator=(const QUnixSocketRights &)
Create a copy of other.
bool setSocketDescriptor(int socketDescriptor)
Sets the socket descriptor to use to socketDescriptor, bypassing QUnixSocket&#39;s connection infrastruct...
const QByteArray & bytes() const
Return the data portion of the message.
virtual ~QUnixSocket()
Destroys the QUnixSocket instance.
bool connect(const QByteArray &path)
Attempt to connect to path.
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
unsigned int dataBufferCapacity
int dupFd() const
Return a duplicate of the file descriptor contained in this object.
QByteArray address() const
Returns the Unix path address passed to QUnixSocket::connect() .
#define slots
Definition: qobjectdefs.h:68
void readyRead()
This signal is emitted once every time new data is available for reading from the device...
~QUnixSocketRights()
Destroys the QUnixSocketRights instance.
#define signals
Definition: qobjectdefs.h:69
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
QSocketNotifier * writeNotifier
virtual void timerEvent(QTimerEvent *)
This event handler can be reimplemented in a subclass to receive timer events for the object...
#define QUNIXSOCKET_DEFAULT_ANCILLARYBUFFER
void deleteLater()
Schedules this object for deletion.
Definition: qobject.cpp:2145
QUnixSocketMessagePrivate(const QByteArray &b, const QList< QUnixSocketRights > &r)
QUnixSocketMessage()
Construct an empty QUnixSocketMessage.
The QUnixSocketMessage class encapsulates a message sent or received through the QUnixSocket class...
Definition: qunixsocket_p.h:92
int errno
static int qt_safe_dup(int oldfd, int atleast=0, int flags=FD_CLOEXEC)
Definition: qcore_unix_p.h:227
#define UNIX_PATH_MAX
Definition: qunixsocket.cpp:63
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition: qobject.cpp:1650
#define QT_CLOSE
Definition: qcore_unix_p.h:304