summaryrefslogtreecommitdiffstats
path: root/src/network/socket
diff options
context:
space:
mode:
authorJoão Abecasis <joao.abecasis@nokia.com>2012-02-21 14:58:57 +0100
committerJoão Abecasis <joao.abecasis@nokia.com>2012-02-21 14:58:57 +0100
commit31a0358afb4fde998d1eeeaa80fc32e4420266c7 (patch)
tree938455353474196c1f49b0529b5b644e19c21f3e /src/network/socket
parent4c8a4058c359c8d163c643120426079fc80c8214 (diff)
parent69da8588d41bbf5ab785f5ad7c1fce76deefc7d0 (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.cpp98
-rw-r--r--src/network/socket/qlocalserver.h17
-rw-r--r--src/network/socket/qlocalserver_p.h5
-rw-r--r--src/network/socket/qlocalserver_tcp.cpp7
-rw-r--r--src/network/socket/qlocalserver_unix.cpp107
-rw-r--r--src/network/socket/qlocalserver_win.cpp6
-rw-r--r--src/network/socket/qlocalsocket.cpp1
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp10
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) {