46 #include <QtCore/qsocketnotifier.h> 47 #include <QtCore/qqueue.h> 48 #include <QtCore/qdatetime.h> 49 #include "private/qcore_unix_p.h" 51 #ifdef QUNIXSOCKET_DEBUG 52 #include <QtCore/qdebug.h> 59 #include <sys/socket.h> 63 #define UNIX_PATH_MAX 108 // From unix(7) 76 # define SO_PASSCRED 16 78 #ifndef SCM_CREDENTIALS 79 # define SCM_CREDENTIALS 0x02 82 # define MSG_DONTWAIT 0x40 85 # define MSG_NOSIGNAL 0x4000 88 #endif // QT_LINUXBASE 135 #ifdef QUNIXSOCKET_DEBUG 139 #ifdef QUNIXSOCKET_DEBUG 141 qDebug() <<
"QUnixSocketRightsPrivate: Unable to close managed" 142 " file descriptor (" << ::strerror(
errno) <<
')';
170 #ifdef QUNIXSOCKET_DEBUG 172 qDebug() <<
"QUnixSocketRights: Unable to duplicate fd " 173 << fd <<
" (" << ::strerror(
errno) <<
')';
240 if(-1 ==
d->
fd)
return -1;
244 #ifdef QUNIXSOCKET_DEBUG 246 qDebug() <<
"QUnixSocketRights: Unable to duplicate managed file " 247 "descriptor (" << ::strerror(
errno) <<
')';
277 : state(
Default), vec(0), iovecLen(0), dataSize(0) {}
279 : bytes(b), state(
Default), vec(0), iovecLen(0), dataSize(0) {}
282 : bytes(b), rights(r), state(
Default), vec(0), iovecLen(0), dataSize(0) {}
284 int size()
const {
return vec ? dataSize : bytes.size(); }
285 void removeBytes(
unsigned int );
314 ::iovec *vecPtr = vec;
315 if ( bytesToDequeue > (
unsigned int)dataSize ) bytesToDequeue = dataSize;
316 while ( bytesToDequeue > 0 && iovecLen > 0 )
318 if ( vecPtr->iov_len > bytesToDequeue )
323 char **
base =
reinterpret_cast<char**
>(&(vecPtr->iov_base));
324 *base += bytesToDequeue;
325 vecPtr->iov_len -= bytesToDequeue;
332 bytesToDequeue -= vecPtr->iov_len;
337 dataSize -= bytesToDequeue;
338 if ( iovecLen == 0 ) vec = 0;
342 bytes.remove(0, bytesToDequeue );
461 for (
int v = 0; v < vecLen; v++ )
592 d->
uid = ::geteuid();
593 d->
gid = ::getegid();
610 d->
gid = ::getegid();
627 d->
uid = ::geteuid();
645 #define QUNIXSOCKET_DEFAULT_READBUFFER 1024 646 #define QUNIXSOCKET_DEFAULT_ANCILLARYBUFFER 0 805 : me(_me), fd(-1), readNotifier(0), writeNotifier(0),
807 writeQueueBytes(0), messageValid(false), dataBuffer(0),
808 dataBufferLength(0), dataBufferCapacity(0), ancillaryBuffer(0),
809 ancillaryBufferCount(0), closingTimer(0) {
817 delete [] dataBuffer;
819 delete [] ancillaryBuffer;
822 enum { CausedAbort = 0x70000000 };
841 if(!messageValid)
return;
842 ::cmsghdr * h = (::cmsghdr *)CMSG_FIRSTHDR(&(message));
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);
849 for(
int ii = 0; ii < numFds; ++ii)
853 h = (::cmsghdr *)CMSG_NXTHDR(&(message), h);
856 messageValid =
false;
867 return CMSG_SPACE(
sizeof(::ucred)) + CMSG_SPACE(
sizeof(
int) * ancillaryBufferCount);
878 killTimer(closingTimer);
883 void bytesWritten(
qint64);
886 void readActivated();
918 Q_ASSERT(readBufferSize > 0 && rightsBufferSize >= 0);
950 #ifdef QUNIXSOCKET_DEBUG 951 qDebug() <<
"QUnixSocket: Connect requested to '" 970 d->
fd = ::socket(PF_UNIX, SOCK_STREAM, 0);
972 #ifdef QUNIXSOCKET_DEBUG 973 qDebug() <<
"QUnixSocket: Unable to create socket (" 974 << strerror(
errno) <<
')';
982 crv = ::setsockopt(
d->
fd, SOL_SOCKET, SO_PASSCRED, (
void *)&_true,
985 #ifdef QUNIXSOCKET_DEBUG 986 qDebug() <<
"QUnixSocket: Unable to configure socket (" 987 << ::strerror(
errno) <<
')';
995 struct ::sockaddr_un addr;
996 addr.sun_family = AF_UNIX;
997 ::memcpy(addr.sun_path, path.
data(), path.
size());
999 addr.sun_path[path.
size()] =
'\0';
1002 crv =
::connect(
d->
fd, (sockaddr *)&addr,
sizeof(sockaddr_un));
1004 #ifdef QUNIXSOCKET_DEBUG 1005 qDebug() <<
"QUnixSocket: Unable to connect (" 1006 << ::strerror(
errno) <<
')';
1008 if(ECONNREFUSED ==
errno)
1010 else if(ENOENT ==
errno)
1024 d,
SLOT(readActivated()));
1026 d,
SLOT(writeActivated()));
1032 #ifdef QUNIXSOCKET_DEBUG 1033 qDebug() <<
"QUnixSocket: Connected to " << path;
1039 #ifdef QUNIXSOCKET_DEBUG 1043 #ifdef QUNIXSOCKET_DEBUG 1045 qDebug() <<
"QUnixSocket: Unable to close file descriptor after " 1046 "failed connect (" << ::strerror(
errno) <<
')';
1075 if(-1 == socketDescriptor) {
1076 #ifdef QUNIXSOCKET_DEBUG 1077 qDebug() <<
"QUnixSocket: User provided socket is invalid";
1085 int crv = ::setsockopt(socketDescriptor, SOL_SOCKET,
1086 SO_PASSCRED, (
void *)&_true,
sizeof(
int));
1088 #ifdef QUNIXSOCKET_DEBUG 1089 qDebug() <<
"QUnixSocket: Unable to configure client provided socket (" 1090 << ::strerror(
errno) <<
')';
1104 d,
SLOT(readActivated()));
1106 d,
SLOT(writeActivated()));
1154 #ifdef QUNIXSOCKET_DEBUG 1158 #ifdef QUNIXSOCKET_DEBUG 1160 qDebug() <<
"QUnixSocket: Unable to close socket during abort (" 1161 << strerror(
errno) <<
')';
1358 qint64 byteSize = CMSG_SPACE(
sizeof(::ucred)) +
1359 CMSG_SPACE(size *
sizeof(
int));
1391 if(socketdata.
d->
size() == 0)
return 0;
1397 return socketdata.
d->
size();
1423 ::cmsghdr * h = (::cmsghdr *)CMSG_FIRSTHDR(&(
d->
message));
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 );
1432 data.
d->
pid = cred->pid;
1433 data.
d->
gid = cred->gid;
1434 data.
d->
uid = cred->uid;
1436 }
else if(SCM_RIGHTS == h->cmsg_type) {
1438 int * fds = (
int *)CMSG_DATA(h);
1439 int numFds = (h->cmsg_len - CMSG_LEN(0)) /
sizeof(
int);
1441 for(
int ii = 0; ii < numFds; ++ii) {
1448 #ifdef QUNIXSOCKET_DEBUG 1449 qFatal(
"QUnixSocket: Unknown ancillary data type (%d) received.",
1455 h = (::cmsghdr *)CMSG_NXTHDR(&(
d->
message), h);
1458 if(
d->
message.msg_flags & MSG_CTRUNC) {
1491 int timeout = msecs;
1493 struct timeval *ptrTv = 0;
1503 FD_SET(
d->
fd, &readset);
1506 tv.tv_sec = timeout / 1000;
1507 tv.tv_usec = (timeout % 1000) * 1000;
1511 int rv =
::select(
d->
fd + 1, &readset, 0, 0, ptrTv);
1526 timeout = msecs - stopWatch.
elapsed();
1528 while (timeout > 0);
1550 FD_SET(
d->
fd, &fdwrite);
1551 int timeout = msecs < 0 ? 0 : msecs - stopWatch.
elapsed();
1553 struct timeval *ptrTv = 0;
1556 tv.tv_sec = timeout / 1000;
1557 tv.tv_usec = (timeout % 1000) * 1000;
1561 int rv =
::select(
d->
fd + 1, 0, &fdwrite, 0, ptrTv);
1571 if (bytesWritten == 0) {
1576 timeout = msecs - stopWatch.
elapsed();
1581 if (delay > timeout)
1587 ::usleep(delay * 1000);
1592 }
while (bytesWritten == 0);
1594 return (bytesWritten != -1);
1619 if(0 >= maxSize)
return 0;
1650 writeNotifier->setEnabled(
false);
1666 ::msghdr sendmessage;
1667 ::bzero(&sendmessage,
sizeof(::msghdr));
1670 sendmessage.msg_iov = m.
d->
vec;
1675 sendmessage.msg_iov = &vec;
1676 sendmessage.msg_iovlen = 1;
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;
1685 ::cmsghdr * h = CMSG_FIRSTHDR(&sendmessage);
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);
1696 sendmessage.msg_controllen -= CMSG_SPACE(
sizeof(::ucred));
1699 for(
int ii = 0; ii < a.
count(); ++ii) {
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);
1709 sendmessage.msg_controllen -= CMSG_SPACE(
sizeof(
int));
1713 #ifdef QUNIXSOCKET_DEBUG 1714 qDebug() <<
"QUnixSocket: Transmitting message (length" << m.
d->
size() <<
')';
1716 ::ssize_t s = ::sendmsg(fd, &sendmessage, MSG_DONTWAIT | MSG_NOSIGNAL);
1717 #ifdef QUNIXSOCKET_DEBUG 1718 qDebug() <<
"QUnixSocket: Transmitted message (" << s <<
')';
1723 writeNotifier->setEnabled(
true);
1724 }
else if(EPIPE ==
errno) {
1725 #ifdef QUNIXSOCKET_DEBUG 1726 qDebug() <<
"QUnixSocket: Remote side disconnected during transmit " 1727 "(" << ::strerror(
errno) <<
')';
1731 #ifdef QUNIXSOCKET_DEBUG 1732 qDebug() <<
"QUnixSocket: Unable to transmit data (" 1733 << ::strerror(
errno) <<
')';
1739 }
else if(s != m.
d->
size()) {
1742 writeNotifier->setEnabled(
true);
1743 delete [] (
char *)sendmessage.msg_control;
1746 writeQueueBytes -= s;
1753 writeQueue.dequeue();
1754 Q_ASSERT(writeQueueBytes >= (
unsigned)s);
1755 writeQueueBytes -= s;
1760 delete [] (
char *)sendmessage.msg_control;
1761 if(-1 != s && !writeQueue.isEmpty())
1762 return writeActivated();
1766 if((-1 == s) && (EAGAIN ==
errno || EWOULDBLOCK ==
errno || EINTR ==
errno))
1775 #ifdef QUNIXSOCKET_DEBUG 1776 qDebug() <<
"QUnixSocket: readActivated";
1778 readNotifier->setEnabled(
false);
1781 vec.iov_base = dataBuffer;
1782 vec.iov_len = dataBufferCapacity;
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;
1791 #ifdef MSG_CMSG_CLOEXEC 1792 flags = MSG_CMSG_CLOEXEC;
1795 int recvrv = ::recvmsg(fd, &message, flags);
1796 #ifdef QUNIXSOCKET_DEBUG 1797 qDebug() <<
"QUnixSocket: Received message (" << recvrv <<
')';
1800 #ifdef QUNIXSOCKET_DEBUG 1801 qDebug() <<
"QUnixSocket: Unable to receive data (" 1802 << ::strerror(
errno) <<
')';
1807 }
else if(0 == recvrv) {
1811 Q_ASSERT((
unsigned)recvrv <= dataBufferCapacity);
1812 dataBufferLength = recvrv;
1813 messageValid =
true;
1815 #ifdef QUNIXSOCKET_DEBUG 1816 qDebug() <<
"QUnixSocket: readyRead() " << dataBufferLength;
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...
void abort()
Abort the connection.
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
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.
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.
QUnixSocket::SocketError error
virtual bool isSequential() const
char * data()
Returns a pointer to the data stored in the byte array.
QUnixSocketPrivate(QUnixSocket *_me)
void start()
Sets this time to the current time.
QSharedDataPointer< QUnixSocketRightsPrivate > d
void detach()
If the shared data object's reference count is greater than 1, this function creates a deep copy of t...
void setProcessId(pid_t)
Set the process id credential associated with this message to pid.
The QByteArray class provides an array of bytes.
bool rightsWereTruncated() const
Returns true if the rights portion of the message was truncated on reception due to insufficient buff...
int select(int, fd_set *, fd_set *, fd_set *, struct timeval *)
virtual ~QUnixSocketRightsPrivate()
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.
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.
The QObject class is the base class of all Qt objects.
void setReadBufferSize(qint64 size)
Sets the size of the socket's read buffer in bytes.
bool flush()
This function writes as much as possible from the internal write buffer to the underlying socket...
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.
QQueue< QUnixSocketMessage > writeQueue
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
The QSocketNotifier class provides support for monitoring activity on a file descriptor.
unsigned int dataBufferLength
static const uint Default
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
void append(const T &t)
Inserts value at the end of the list.
The QTime class provides clock time functions.
#define QT_BEGIN_NAMESPACE
This macro expands to.
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...
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.
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.
QUnixSocketMessage & operator=(const QUnixSocketMessage &)
Assign the contents of other to this object.
unsigned int ancillaryBufferCapacity()
QUnixSocketMessagePrivate()
#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.
void setRightsBufferSize(qint64 size)
Sets the size of the socket'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...
void enqueue(const T &t)
Adds value t to the tail of the queue.
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.
The QTimerEvent class contains parameters that describe a timer event.
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.
int size() const
Returns the number of items in the list.
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
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.
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'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.
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() .
void readyRead()
This signal is emitted once every time new data is available for reading from the device...
~QUnixSocketRights()
Destroys the QUnixSocketRights instance.
The QIODevice class is the base interface class of all I/O devices in Qt.
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.
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...
static int qt_safe_dup(int oldfd, int atleast=0, int flags=FD_CLOEXEC)
void killTimer(int id)
Kills the timer with timer identifier, id.