summaryrefslogtreecommitdiffstats
path: root/src/gui/embedded/qunixsocketserver.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 09:34:13 (GMT)
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 09:34:13 (GMT)
commit67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch)
tree1dbf50b3dff8d5ca7e9344733968c72704eb15ff /src/gui/embedded/qunixsocketserver.cpp
downloadQt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip
Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz
Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2
Long live Qt!
Diffstat (limited to 'src/gui/embedded/qunixsocketserver.cpp')
-rw-r--r--src/gui/embedded/qunixsocketserver.cpp376
1 files changed, 376 insertions, 0 deletions
diff --git a/src/gui/embedded/qunixsocketserver.cpp b/src/gui/embedded/qunixsocketserver.cpp
new file mode 100644
index 0000000..6e9347b
--- /dev/null
+++ b/src/gui/embedded/qunixsocketserver.cpp
@@ -0,0 +1,376 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qunixsocketserver_p.h"
+
+// #define QUNIXSOCKETSERVER_DEBUG
+
+#ifdef QUNIXSOCKETSERVER_DEBUG
+#include <QDebug>
+#endif
+
+#include <QtCore/qsocketnotifier.h>
+
+extern "C" {
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <errno.h>
+};
+
+#define UNIX_PATH_MAX 108 // From unix(7)
+
+QT_BEGIN_NAMESPACE
+
+class QUnixSocketServerPrivate : public QObject
+{
+Q_OBJECT
+public:
+ QUnixSocketServerPrivate(QUnixSocketServer * parent)
+ : QObject(), me(parent), fd(-1), maxConns(30),
+ error(QUnixSocketServer::NoError), acceptNotifier(0)
+ {}
+
+ QUnixSocketServer * me;
+ int fd;
+ int maxConns;
+ QByteArray address;
+ QUnixSocketServer::ServerError error;
+ QSocketNotifier * acceptNotifier;
+public slots:
+ void acceptActivated();
+};
+
+/*!
+ \class QUnixSocketServer
+ \internal
+
+ \brief The QUnixSocketServer class provides a Unix domain socket based server.
+ \omit
+ \ingroup Platform::DeviceSpecific
+ \ingroup Platform::OS
+ \ingroup Platform::Communications
+ \endomit
+ \ingroup qws
+
+ This class makes it possible to accept incoming Unix domain socket
+ connections. Call \l QUnixSocketServer::listen() to have the server listen
+ for incoming connections on a specified path. The pure virtual
+ \l QUnixSocketServer::incomingConnection() is called each time a new
+ connection is established. Users must inherit from QUnixSocketServer and
+ implement this method.
+
+ If an error occurs, \l QUnixSocketServer::serverError() returns the type of
+ error. Errors can only occur during server establishment - that is, during a
+ call to \l QUnixSocketServer::listen(). Calling \l QUnixSocketServer::close()
+ causes QUnixSocketServer to stop listening for connections and reset its
+ state.
+
+ QUnixSocketServer is often used in conjunction with the \l QUnixSocket class.
+
+ \sa QUnixSocket
+*/
+
+/*!
+ \enum QUnixSocketServer::ServerError
+
+ The ServerError enumeration represents the errors that can occur during server
+ establishment. The most recent error can be retrieved through a call to
+ \l QUnixSocketServer::serverError().
+
+ \value NoError No error has occurred.
+ \value InvalidPath An invalid path endpoint was passed to
+ \l QUnixSocketServer::listen(). As defined by unix(7), invalid paths
+ include an empty path, or what more than 107 characters long.
+ \value ResourceError An error acquiring or manipulating the system's socket
+ resources occurred. For example, if the process runs out of available
+ socket descriptors, a ResourceError will occur.
+ \value BindError The server was unable to bind to the specified path.
+ \value ListenError The server was unable to listen on the specified path for
+ incoming connections.
+ */
+
+/*!
+ Create a new Unix socket server with the given \a parent.
+ */
+QUnixSocketServer::QUnixSocketServer(QObject *parent)
+: QObject(parent), d(0)
+{
+}
+
+/*!
+ Stops listening for incoming connection and destroys the Unix socket server.
+ */
+QUnixSocketServer::~QUnixSocketServer()
+{
+ close();
+ if(d)
+ delete d;
+}
+
+/*!
+ Stop listening for incoming connections and resets the Unix socket server's
+ state. Calling this method while \l {QUnixSocketServer::isListening()}{not listening } for incoming connections is a no-op.
+
+ \sa QUnixSocketServer::listen()
+ */
+void QUnixSocketServer::close()
+{
+ if(!d)
+ return;
+
+ if(d->acceptNotifier) {
+ d->acceptNotifier->setEnabled(false);
+ delete d->acceptNotifier;
+ }
+ d->acceptNotifier = 0;
+
+ if(-1 != d->fd) {
+#ifdef QUNIXSOCKET_DEBUG
+ int closerv =
+#endif
+ ::close(d->fd);
+#ifdef QUNIXSOCKET_DEBUG
+ if(0 != closerv) {
+ qDebug() << "QUnixSocketServer: Unable to close socket ("
+ << strerror(errno) << ")";
+ }
+#endif
+ }
+ d->fd = -1;
+ d->address = QByteArray();
+ d->error = NoError;
+}
+
+/*!
+ Returns the last server error. Errors may only occur within a call to
+ \l QUnixSocketServer::listen(), and only when such a call fails.
+
+ This method is not destructive, so multiple calls to
+ QUnixSocketServer::serverError() will return the same value. The error is
+ only reset by an explicit call to \l QUnixSocketServer::close() or
+ by further calls to \l QUnixSocketServer::listen().
+ */
+QUnixSocketServer::ServerError QUnixSocketServer::serverError() const
+{
+ if(!d)
+ return NoError;
+
+ return d->error;
+}
+
+/*!
+ Returns true if this server is listening for incoming connections, false
+ otherwise.
+
+ \sa QUnixSocketServer::listen()
+ */
+bool QUnixSocketServer::isListening() const
+{
+ if(!d)
+ return false;
+
+ return (-1 != d->fd);
+}
+
+/*!
+ Tells the server to listen for incoming connections on \a path. Returns true
+ if it successfully initializes, false otherwise. In the case of failure, the
+ \l QUnixSocketServer::serverError() error status is set accordingly.
+
+ Calling this method while the server is already running will result in the
+ server begin reset, and then attempting to listen on \a path. This will not
+ affect connections established prior to the server being reset, but further
+ incoming connections on the previous path will be refused.
+
+ The server can be explicitly reset by a call to \l QUnixSocketServer::close().
+
+ \sa QUnixSocketServer::close()
+ */
+bool QUnixSocketServer::listen(const QByteArray & path)
+{
+ if(d) {
+ close(); // Any existing server is destroyed
+ } else {
+ d = new QUnixSocketServerPrivate(this);
+ }
+
+ if(path.isEmpty() || path.size() > UNIX_PATH_MAX) {
+ d->error = InvalidPath;
+ return false;
+ }
+ unlink( path ); // ok if this fails
+
+ // Create the socket
+ d->fd = ::socket(PF_UNIX, SOCK_STREAM, 0);
+ if(-1 == d->fd) {
+#ifdef QUNIXSOCKETSERVER_DEBUG
+ qDebug() << "QUnixSocketServer: Unable to create socket ("
+ << strerror(errno) << ")";
+#endif
+ close();
+ d->error = ResourceError;
+ return false;
+ }
+
+ // Construct our unix address
+ struct ::sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ ::memcpy(addr.sun_path, path.data(), path.size());
+ if(path.size() < UNIX_PATH_MAX)
+ addr.sun_path[path.size()] = '\0';
+
+ // Attempt to bind
+ if(-1 == ::bind(d->fd, (sockaddr *)&addr, sizeof(sockaddr_un))) {
+#ifdef QUNIXSOCKETSERVER_DEBUG
+ qDebug() << "QUnixSocketServer: Unable to bind socket ("
+ << strerror(errno) << ")";
+#endif
+ close();
+ d->error = BindError;
+ return false;
+ }
+
+ // Listen to socket
+ if(-1 == ::listen(d->fd, d->maxConns)) {
+#ifdef QUNIXSOCKETSERVER_DEBUG
+ qDebug() << "QUnixSocketServer: Unable to listen socket ("
+ << strerror(errno) << ")";
+#endif
+ close();
+ d->error = ListenError;
+ return false;
+ }
+
+ // Success!
+ d->address = path;
+ d->acceptNotifier = new QSocketNotifier(d->fd, QSocketNotifier::Read, d);
+ d->acceptNotifier->setEnabled(true);
+ QObject::connect(d->acceptNotifier, SIGNAL(activated(int)),
+ d, SLOT(acceptActivated()));
+
+ return true;
+}
+
+/*!
+ Returns the Unix path on which this server is listening. If this server is
+ not listening, and empty address will be returned.
+ */
+QByteArray QUnixSocketServer::serverAddress() const
+{
+ if(!d)
+ return QByteArray();
+ return d->address;
+}
+
+int QUnixSocketServer::socketDescriptor() const
+{
+ if (!d)
+ return -1;
+ return d->fd;
+}
+
+
+/*!
+ Returns the maximum length the queue of pending connections may grow to. That
+ is, the maximum number of clients attempting to connect for which the Unix
+ socket server has not yet accepted and passed to
+ \l QUnixSocketServer::incomingConnection(). If a connection request arrives
+ with the queue full, the client may receive a connection refused notification.
+
+ By default a queue length of 30 is used.
+
+ \sa QUnixSocketServer::setMaxPendingConnections()
+ */
+int QUnixSocketServer::maxPendingConnections() const
+{
+ if(!d)
+ return 30;
+
+ return d->maxConns;
+}
+
+/*!
+ Sets the maximum length the queue of pending connections may grow to
+ \a numConnections. This value will only apply to
+ \l QUnixSocketServer::listen() calls made following the value change - it will
+ not be retroactively applied.
+
+ \sa QUnixSocketServer::maxPendingConnections()
+ */
+void QUnixSocketServer::setMaxPendingConnections(int numConnections)
+{
+ Q_ASSERT(numConnections >= 1);
+ if(!d)
+ d = new QUnixSocketServerPrivate(this);
+
+ d->maxConns = numConnections;
+}
+
+/*!
+ \fn void QUnixSocketServer::incomingConnection(int socketDescriptor)
+
+ This method is invoked each time a new incoming connection is established with
+ the server. Clients must reimplement this function in their QUnixSocketServer
+ derived class to handle the connection.
+
+ A common approach to handling the connection is to pass \a socketDescriptor to
+ a QUnixSocket instance.
+
+ \sa QUnixSocket
+ */
+
+void QUnixSocketServerPrivate::acceptActivated()
+{
+ ::sockaddr_un r;
+ socklen_t len = sizeof(sockaddr_un);
+ int connsock = ::accept(fd, (sockaddr *)&r, &len);
+#ifdef QUNIXSOCKETSERVER_DEBUG
+ qDebug() << "QUnixSocketServer: Accept connection " << connsock;
+#endif
+ if(-1 != connsock)
+ me->incomingConnection(connsock);
+}
+
+QT_END_NAMESPACE
+
+#include "qunixsocketserver.moc"