Track API change in QPlatformNativeInterface
[profile/ivi/qtbase.git] / src / gui / embedded / qunixsocketserver.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qunixsocketserver_p.h"
43
44 // #define QUNIXSOCKETSERVER_DEBUG
45
46 #ifdef QUNIXSOCKETSERVER_DEBUG
47 #include <QDebug>
48 #endif
49
50 #include <QtCore/qsocketnotifier.h>
51
52 extern "C" {
53 #include <sys/types.h>
54 #include <sys/socket.h>
55 #include <sys/un.h>
56 #include <unistd.h>
57 #include <errno.h>
58 };
59
60 #define UNIX_PATH_MAX 108 // From unix(7)
61
62 QT_BEGIN_NAMESPACE
63
64 class QUnixSocketServerPrivate : public QObject
65 {
66 Q_OBJECT
67 public:
68     QUnixSocketServerPrivate(QUnixSocketServer * parent)
69     : QObject(), me(parent), fd(-1), maxConns(30),
70       error(QUnixSocketServer::NoError), acceptNotifier(0)
71     {}
72
73     QUnixSocketServer * me;
74     int fd;
75     int maxConns;
76     QByteArray address;
77     QUnixSocketServer::ServerError error;
78     QSocketNotifier * acceptNotifier;
79 public slots:
80     void acceptActivated();
81 };
82
83 /*!
84   \class QUnixSocketServer
85   \internal
86
87   \brief The QUnixSocketServer class provides a Unix domain socket based server.
88   \omit
89   \ingroup Platform::DeviceSpecific
90   \ingroup Platform::OS
91   \ingroup Platform::Communications
92   \endomit
93   \ingroup qws
94
95   This class makes it possible to accept incoming Unix domain socket
96   connections.  Call \l QUnixSocketServer::listen() to have the server listen
97   for incoming connections on a specified path.  The pure virtual
98   \l QUnixSocketServer::incomingConnection() is called each time a new
99   connection is established.  Users must inherit from QUnixSocketServer and
100   implement this method.
101
102   If an error occurs, \l QUnixSocketServer::serverError() returns the type of
103   error.  Errors can only occur during server establishment - that is, during a
104   call to \l QUnixSocketServer::listen().  Calling \l QUnixSocketServer::close()
105   causes QUnixSocketServer to stop listening for connections and reset its
106   state.
107
108   QUnixSocketServer is often used in conjunction with the \l QUnixSocket class.
109
110   \sa QUnixSocket
111 */
112
113 /*!
114   \enum QUnixSocketServer::ServerError
115
116   The ServerError enumeration represents the errors that can occur during server
117   establishment.  The most recent error can be retrieved through a call to
118   \l QUnixSocketServer::serverError().
119
120   \value NoError No error has occurred.
121   \value InvalidPath An invalid path endpoint was passed to
122          \l QUnixSocketServer::listen().  As defined by unix(7), invalid paths
123          include an empty path, or what more than 107 characters long.
124   \value ResourceError An error acquiring or manipulating the system's socket
125          resources occurred.  For example, if the process runs out of available
126          socket descriptors, a ResourceError will occur.
127   \value BindError The server was unable to bind to the specified path.
128   \value ListenError The server was unable to listen on the specified path for
129          incoming connections.
130   */
131
132 /*!
133   Create a new Unix socket server with the given \a parent.
134   */
135 QUnixSocketServer::QUnixSocketServer(QObject *parent)
136 : QObject(parent), d(0)
137 {
138 }
139
140 /*!
141   Stops listening for incoming connection and destroys the Unix socket server.
142   */
143 QUnixSocketServer::~QUnixSocketServer()
144 {
145     close();
146     if(d)
147         delete d;
148 }
149
150 /*!
151   Stop listening for incoming connections and resets the Unix socket server's
152   state.  Calling this method while \l {QUnixSocketServer::isListening()}{not listening } for incoming connections is a no-op.
153
154   \sa QUnixSocketServer::listen()
155   */
156 void QUnixSocketServer::close()
157 {
158     if(!d)
159         return;
160
161     if(d->acceptNotifier) {
162         d->acceptNotifier->setEnabled(false);
163         delete d->acceptNotifier;
164     }
165     d->acceptNotifier = 0;
166
167     if(-1 != d->fd) {
168 #ifdef QUNIXSOCKET_DEBUG
169         int closerv =
170 #endif
171             ::close(d->fd);
172 #ifdef QUNIXSOCKET_DEBUG
173         if(0 != closerv) {
174             qDebug() << "QUnixSocketServer: Unable to close socket ("
175                      << strerror(errno) << ')';
176         }
177 #endif
178     }
179     d->fd = -1;
180     d->address = QByteArray();
181     d->error = NoError;
182 }
183
184 /*!
185   Returns the last server error.  Errors may only occur within a call to
186   \l QUnixSocketServer::listen(), and only when such a call fails.
187
188   This method is not destructive, so multiple calls to
189   QUnixSocketServer::serverError() will return the same value.  The error is
190   only reset by an explicit call to \l QUnixSocketServer::close() or
191   by further calls to \l QUnixSocketServer::listen().
192   */
193 QUnixSocketServer::ServerError QUnixSocketServer::serverError() const
194 {
195     if(!d)
196         return NoError;
197
198     return d->error;
199 }
200
201 /*!
202   Returns true if this server is listening for incoming connections, false
203   otherwise.
204
205   \sa QUnixSocketServer::listen()
206   */
207 bool QUnixSocketServer::isListening() const
208 {
209     if(!d)
210         return false;
211
212     return (-1 != d->fd);
213 }
214
215 /*!
216   Tells the server to listen for incoming connections on \a path.  Returns true
217   if it successfully initializes, false otherwise.  In the case of failure, the
218   \l QUnixSocketServer::serverError() error status is set accordingly.
219
220   Calling this method while the server is already running will result in the
221   server begin reset, and then attempting to listen on \a path.  This will not
222   affect connections established prior to the server being reset, but further
223   incoming connections on the previous path will be refused.
224
225   The server can be explicitly reset by a call to \l QUnixSocketServer::close().
226
227   \sa QUnixSocketServer::close()
228   */
229 bool QUnixSocketServer::listen(const QByteArray & path)
230 {
231     if(d) {
232         close(); // Any existing server is destroyed
233     } else {
234         d = new QUnixSocketServerPrivate(this);
235     }
236
237     if(path.isEmpty() || path.size() > UNIX_PATH_MAX) {
238         d->error = InvalidPath;
239         return false;
240     }
241     unlink( path );  // ok if this fails
242
243     // Create the socket
244     d->fd = ::socket(PF_UNIX, SOCK_STREAM, 0);
245     if(-1 == d->fd) {
246 #ifdef QUNIXSOCKETSERVER_DEBUG
247         qDebug() << "QUnixSocketServer: Unable to create socket ("
248                  << strerror(errno) << ')';
249 #endif
250         close();
251         d->error = ResourceError;
252         return false;
253     }
254
255     // Construct our unix address
256     struct ::sockaddr_un addr;
257     addr.sun_family = AF_UNIX;
258     ::memcpy(addr.sun_path, path.data(), path.size());
259     if(path.size() < UNIX_PATH_MAX)
260         addr.sun_path[path.size()] = '\0';
261
262     // Attempt to bind
263     if(-1 == ::bind(d->fd, (sockaddr *)&addr, sizeof(sockaddr_un))) {
264 #ifdef QUNIXSOCKETSERVER_DEBUG
265         qDebug() << "QUnixSocketServer: Unable to bind socket ("
266                  << strerror(errno) << ')';
267 #endif
268         close();
269         d->error = BindError;
270         return false;
271     }
272
273     // Listen to socket
274     if(-1 == ::listen(d->fd, d->maxConns)) {
275 #ifdef QUNIXSOCKETSERVER_DEBUG
276         qDebug() << "QUnixSocketServer: Unable to listen socket ("
277                  << strerror(errno) << ')';
278 #endif
279         close();
280         d->error = ListenError;
281         return false;
282     }
283
284     // Success!
285     d->address = path;
286     d->acceptNotifier = new QSocketNotifier(d->fd, QSocketNotifier::Read, d);
287     d->acceptNotifier->setEnabled(true);
288     QObject::connect(d->acceptNotifier, SIGNAL(activated(int)),
289                      d, SLOT(acceptActivated()));
290
291     return true;
292 }
293
294 /*!
295   Returns the Unix path on which this server is listening.  If this server is
296   not listening, and empty address will be returned.
297   */
298 QByteArray QUnixSocketServer::serverAddress() const
299 {
300     if(!d)
301         return QByteArray();
302     return d->address;
303 }
304
305 int QUnixSocketServer::socketDescriptor() const
306 {
307     if (!d)
308         return -1;
309     return d->fd;
310 }
311
312
313 /*!
314   Returns the maximum length the queue of pending connections may grow to.  That
315   is, the maximum number of clients attempting to connect for which the Unix
316   socket server has not yet accepted and passed to
317   \l QUnixSocketServer::incomingConnection().  If a connection request arrives
318   with the queue full, the client may receive a connection refused notification.
319
320   By default a queue length of 30 is used.
321
322   \sa QUnixSocketServer::setMaxPendingConnections()
323   */
324 int QUnixSocketServer::maxPendingConnections() const
325 {
326     if(!d)
327         return 30;
328
329     return d->maxConns;
330 }
331
332 /*!
333   Sets the maximum length the queue of pending connections may grow to
334   \a numConnections.  This value will only apply to
335   \l QUnixSocketServer::listen() calls made following the value change - it will
336   not be retroactively applied.
337
338   \sa QUnixSocketServer::maxPendingConnections()
339   */
340 void QUnixSocketServer::setMaxPendingConnections(int numConnections)
341 {
342     Q_ASSERT(numConnections >= 1);
343     if(!d)
344         d = new QUnixSocketServerPrivate(this);
345
346     d->maxConns = numConnections;
347 }
348
349 /*!
350   \fn void QUnixSocketServer::incomingConnection(int socketDescriptor)
351
352   This method is invoked each time a new incoming connection is established with
353   the server.  Clients must reimplement this function in their QUnixSocketServer
354   derived class to handle the connection.
355
356   A common approach to handling the connection is to pass \a socketDescriptor to
357   a QUnixSocket instance.
358
359   \sa QUnixSocket
360   */
361
362 void QUnixSocketServerPrivate::acceptActivated()
363 {
364     ::sockaddr_un r;
365     socklen_t len = sizeof(sockaddr_un);
366     int connsock = ::accept(fd, (sockaddr *)&r, &len);
367 #ifdef QUNIXSOCKETSERVER_DEBUG
368     qDebug() << "QUnixSocketServer: Accept connection " << connsock;
369 #endif
370     if(-1 != connsock)
371         me->incomingConnection(connsock);
372 }
373
374 QT_END_NAMESPACE
375
376 #include "qunixsocketserver.moc"