diff options
author | João Abecasis <joao.abecasis@nokia.com> | 2012-02-21 14:58:57 +0100 |
---|---|---|
committer | João Abecasis <joao.abecasis@nokia.com> | 2012-02-21 14:58:57 +0100 |
commit | 31a0358afb4fde998d1eeeaa80fc32e4420266c7 (patch) | |
tree | 938455353474196c1f49b0529b5b644e19c21f3e /src/network/socket | |
parent | 4c8a4058c359c8d163c643120426079fc80c8214 (diff) | |
parent | 69da8588d41bbf5ab785f5ad7c1fce76deefc7d0 (diff) |
Merge remote-tracking branch 'gerrit/master' into containers
Conflicts:
src/corelib/tools/qbytearray.h
Change-Id: I03b1f3e05c9b7a45130887c522fcd9b7aa387129
Diffstat (limited to 'src/network/socket')
-rw-r--r-- | src/network/socket/qlocalserver.cpp | 98 | ||||
-rw-r--r-- | src/network/socket/qlocalserver.h | 17 | ||||
-rw-r--r-- | src/network/socket/qlocalserver_p.h | 5 | ||||
-rw-r--r-- | src/network/socket/qlocalserver_tcp.cpp | 7 | ||||
-rw-r--r-- | src/network/socket/qlocalserver_unix.cpp | 107 | ||||
-rw-r--r-- | src/network/socket/qlocalserver_win.cpp | 6 | ||||
-rw-r--r-- | src/network/socket/qlocalsocket.cpp | 1 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_win.cpp | 10 |
8 files changed, 248 insertions, 3 deletions
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index b3fe4ac448..e9848213d8 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE /*! \class QLocalServer \since 4.4 + \inmodule QtNetwork \brief The QLocalServer class provides a local socket based server. @@ -82,6 +83,27 @@ QT_BEGIN_NAMESPACE */ /*! + \enum QLocalServer::SocketOption + + This enum describes the possible options that can be used to create the + socket. This changes the access permissions on platforms (Linux, Windows) + that support access permissions on the socket. Both GroupAccess and OtherAccess + may vary slightly in meanings depending on the platform. + + \value UserAccess + Access is restricted to the same user as the process that created the socket. + \value GroupAccess + Access is restricted to the same group but not the user that created the socket on Linux. + \value OtherAccess + Access is available to everyone but the user and group that created the socket on Linux. + \value WorldAccess + No access restrictions. + + \sa SocketOptions +*/ + + +/*! Create a new local socket server with the given \a parent. \sa listen() @@ -109,6 +131,48 @@ QLocalServer::~QLocalServer() } /*! + \property QLocalServer::socketOptions + \since 5.0 + + The setSocketOptions method controls how the socket operates. + For example the socket may restrict access to what user ids can + connect to the socket. + + These options must be set before listen() is called. + + In some cases, such as with Unix domain sockets on Linux, the + access to the socket will be determined by file system permissions, + and are created based on the umask. Setting the access flags will + overide this and will restrict or permit access as specified. + + Other Unix-based operating systems, such as Mac OS X, do not + honor file permissions for Unix domain sockets and by default + have WorldAccess and these permission flags will have no effect. + + By default none of the flags are set, access permissions + are the platform default. + + \sa listen() +*/ +void QLocalServer::setSocketOptions(SocketOptions options) +{ + Q_D(QLocalServer); + + d->socketOptions = options; +} + +/*! + Returns the socket options set on the socket. + + \sa setSocketOptions() + */ +QLocalServer::SocketOptions QLocalServer::socketOptions() const +{ + Q_D(const QLocalServer); + return d->socketOptions; +} + +/*! Stop listening for incoming connections. Existing connections are not effected, but any new connections will be refused. @@ -236,6 +300,40 @@ bool QLocalServer::listen(const QString &name) } /*! + \since 5.0 + + Instructs the server to listen for incoming connections on + \a socketDescriptor. The property returns \c false if the server is + currently listening. It returns \c true on success; otherwise, + it returns \c false. The socket must be ready to accept + new connections with no extra platform-specific functions + called. The socket is set into non-blocking mode. + + serverName(), fullServerName() may return a string with + a name if this option is supported by the platform; + otherwise, they return an empty QString. + + \sa isListening(), close() + */ +bool QLocalServer::listen(qintptr socketDescriptor) +{ + Q_D(QLocalServer); + if (isListening()) { + qWarning("QLocalServer::listen() called when already listening"); + return false; + } + + d->serverName.clear(); + d->fullServerName.clear(); + + if (!d->listen(socketDescriptor)) { + return false; + } + + return true; +} + +/*! Returns the maximum number of pending accepted connections. The default is 30. diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h index f694131953..291122e10d 100644 --- a/src/network/socket/qlocalserver.h +++ b/src/network/socket/qlocalserver.h @@ -58,11 +58,22 @@ class Q_NETWORK_EXPORT QLocalServer : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QLocalServer) + Q_PROPERTY(SocketOptions socketOptions READ socketOptions WRITE setSocketOptions) + Q_FLAGS(SocketOption SocketOptions) Q_SIGNALS: void newConnection(); public: + enum SocketOption { + NoOptions = 0x0, + UserAccessOption = 0x01, + GroupAccessOption = 0x2, + OtherAccessOption = 0x4, + WorldAccessOption = 0x7 + }; + Q_DECLARE_FLAGS(SocketOptions, SocketOption) + QLocalServer(QObject *parent = 0); ~QLocalServer(); @@ -71,6 +82,7 @@ public: virtual bool hasPendingConnections() const; bool isListening() const; bool listen(const QString &name); + bool listen(qintptr socketDescriptor); int maxPendingConnections() const; virtual QLocalSocket *nextPendingConnection(); QString serverName() const; @@ -80,6 +92,9 @@ public: void setMaxPendingConnections(int numConnections); bool waitForNewConnection(int msec = 0, bool *timedOut = 0); + void setSocketOptions(SocketOptions options); + SocketOptions socketOptions() const; + protected: virtual void incomingConnection(quintptr socketDescriptor); @@ -88,6 +103,8 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection()) }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QLocalServer::SocketOptions) + #endif // QT_NO_LOCALSERVER QT_END_NAMESPACE diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h index 6e39136dd4..84081159c7 100644 --- a/src/network/socket/qlocalserver_p.h +++ b/src/network/socket/qlocalserver_p.h @@ -80,12 +80,14 @@ public: #if !defined(QT_LOCALSOCKET_TCP) && !defined(Q_OS_WIN) listenSocket(-1), socketNotifier(0), #endif - maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError) + maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError), + socketOptions(QLocalServer::NoOptions) { } void init(); bool listen(const QString &name); + bool listen(qintptr socketDescriptor); static bool removeServer(const QString &name); void closeServer(); void waitForNewConnection(int msec, bool *timedOut); @@ -121,6 +123,7 @@ public: QQueue<QLocalSocket*> pendingConnections; QString errorString; QAbstractSocket::SocketError error; + QLocalServer::SocketOptions socketOptions; }; QT_END_NAMESPACE diff --git a/src/network/socket/qlocalserver_tcp.cpp b/src/network/socket/qlocalserver_tcp.cpp index d6c6a1af92..9ac1bfaf0e 100644 --- a/src/network/socket/qlocalserver_tcp.cpp +++ b/src/network/socket/qlocalserver_tcp.cpp @@ -78,6 +78,13 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) return true; } +bool QLocalServerPrivate::listen(qintptr socketDescriptor) +{ + Q_Q(QLocalServer); + + return tcpServer.setSocketDescriptor(socketDescriptor); +} + void QLocalServerPrivate::closeServer() { QSettings settings(QLatin1String("Trolltech"), QLatin1String("Qt")); diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index c4482dadfc..0c2edef578 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -44,6 +44,7 @@ #include "qlocalsocket.h" #include "qlocalsocket_p.h" #include "qnet_unix_p.h" +#include "qtemporarydir.h" #ifndef QT_NO_LOCALSERVER @@ -92,6 +93,20 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) } serverName = requestedServerName; + QString tempPath; + QScopedPointer<QTemporaryDir> tempDir; + + // Check any of the flags + if (socketOptions & QLocalServer::WorldAccessOption) { + tempDir.reset(new QTemporaryDir(fullServerName)); + if (!tempDir->isValid()) { + setError(QLatin1String("QLocalServer::listen")); + return false; + } + tempPath = tempDir->path(); + tempPath += QLatin1Char('/') + requestedServerName; + } + // create the unix socket listenSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0); if (-1 == listenSocket) { @@ -108,8 +123,26 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) closeServer(); return false; } - ::memcpy(addr.sun_path, fullServerName.toLatin1().data(), - fullServerName.toLatin1().size() + 1); + + if (socketOptions & QLocalServer::WorldAccessOption) { + if (sizeof(addr.sun_path) < (uint)tempPath.toLatin1().size() + 1) { + setError(QLatin1String("QLocalServer::listen")); + closeServer(); + return false; + } + ::memcpy(addr.sun_path, tempPath.toLatin1().data(), + tempPath.toLatin1().size() + 1); + + if (-1 == ::fchmod(listenSocket, 0)) { + setError(QLatin1String("QLocalServer::listen")); + closeServer(); + return false; + } + + } else { + ::memcpy(addr.sun_path, fullServerName.toLatin1().data(), + fullServerName.toLatin1().size() + 1); + } // bind if(-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un))) { @@ -133,6 +166,76 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) QFile::remove(fullServerName); return false; } + + if (socketOptions & QLocalServer::WorldAccessOption) { + mode_t mode = 000; + + if (socketOptions & QLocalServer::UserAccessOption) { + mode |= S_IRWXU; + } + if (socketOptions & QLocalServer::GroupAccessOption) { + mode |= S_IRWXG; + } + if (socketOptions & QLocalServer::OtherAccessOption) { + mode |= S_IRWXO; + } + + if (mode) { + if (-1 == ::chmod(tempPath.toLatin1(), mode)) { + setError(QLatin1String("QLocalServer::listen")); + closeServer(); + return false; + } + } + if (-1 == ::rename(tempPath.toLatin1(), fullServerName.toLatin1())){ + setError(QLatin1String("QLocalServer::listen")); + closeServer(); + return false; + } + } + + Q_ASSERT(!socketNotifier); + socketNotifier = new QSocketNotifier(listenSocket, + QSocketNotifier::Read, q); + q->connect(socketNotifier, SIGNAL(activated(int)), + q, SLOT(_q_onNewConnection())); + socketNotifier->setEnabled(maxPendingConnections > 0); + return true; +} + +bool QLocalServerPrivate::listen(qintptr socketDescriptor) +{ + Q_Q(QLocalServer); + + // Attach to the localsocket + listenSocket = socketDescriptor; + + ::fcntl(listenSocket, F_SETFD, FD_CLOEXEC); + ::fcntl(listenSocket, F_SETFL, ::fcntl(listenSocket, F_GETFL) | O_NONBLOCK); + +#ifdef Q_OS_LINUX + struct ::sockaddr_un addr; + socklen_t len; + memset(&addr, 0, sizeof(addr)); + if (0 == ::getsockname(listenSocket, (sockaddr *)&addr, &len)) { + // check for absract sockets + if (addr.sun_family == PF_UNIX && addr.sun_path[0] == 0) { + addr.sun_path[0] = '@'; + } + QString name = QString::fromLatin1(addr.sun_path); + if (!name.isEmpty()) { + fullServerName = name; + serverName = fullServerName.mid(fullServerName.lastIndexOf(QLatin1String("/"))+1); + if (serverName.isEmpty()) { + serverName = fullServerName; + } + } + } +#else + serverName.clear(); + fullServerName.clear(); +#endif + Q_ASSERT(!socketNotifier); socketNotifier = new QSocketNotifier(listenSocket, QSocketNotifier::Read, q); diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp index 67e319cdbb..07357e5789 100644 --- a/src/network/socket/qlocalserver_win.cpp +++ b/src/network/socket/qlocalserver_win.cpp @@ -144,6 +144,12 @@ bool QLocalServerPrivate::listen(const QString &name) return true; } +bool QLocalServerPrivate::listen(qintptr) +{ + qWarning("QLocalServer::listen(qintptr) is not supported on Windows QTBUG-24230"); + return false; +} + void QLocalServerPrivate::_q_onNewConnection() { Q_Q(QLocalServer); diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index 3097eaa96c..ced7bba09b 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE /*! \class QLocalSocket \since 4.4 + \inmodule QtNetwork \brief The QLocalSocket class provides a local socket. diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index e57bfcb52b..d7bbe7eb86 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -615,6 +615,16 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); +#if defined (IPV6_V6ONLY) + if (socketProtocol == QAbstractSocket::IPv6Protocol && address.toIPv4Address()) { + //IPV6_V6ONLY option must be cleared to connect to a V4 mapped address + if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) { + DWORD ipv6only = 0; + ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); + } + } +#endif + forever { int connectResult = ::WSAConnect(socketDescriptor, sockAddrPtr, sockAddrSize, 0,0,0,0); if (connectResult == SOCKET_ERROR) { |