source: trunk/src/network/socket/qtcpserver.cpp@ 352

Last change on this file since 352 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 18.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42//#define QTCPSERVER_DEBUG
43
44/*! \class QTcpServer
45
46 \brief The QTcpServer class provides a TCP-based server.
47
48 \reentrant
49 \ingroup io
50 \inmodule QtNetwork
51
52 This class makes it possible to accept incoming TCP connections.
53 You can specify the port or have QTcpServer pick one
54 automatically. You can listen on a specific address or on all the
55 machine's addresses.
56
57 Call listen() to have the server listen for incoming connections.
58 The newConnection() signal is then emitted each time a client
59 connects to the server.
60
61 Call nextPendingConnection() to accept the pending connection as
62 a connected QTcpSocket. The function returns a pointer to a
63 QTcpSocket in QAbstractSocket::ConnectedState that you can use for
64 communicating with the client.
65
66 If an error occurs, serverError() returns the type of error, and
67 errorString() can be called to get a human readable description of
68 what happened.
69
70 When listening for connections, the address and port on which the
71 server is listening are available as serverAddress() and
72 serverPort().
73
74 Calling close() makes QTcpServer stop listening for incoming
75 connections.
76
77 Although QTcpServer is mostly designed for use with an event
78 loop, it's possible to use it without one. In that case, you must
79 use waitForNewConnection(), which blocks until either a
80 connection is available or a timeout expires.
81
82 \sa QTcpSocket, {Fortune Server Example}, {Threaded Fortune Server Example},
83 {Loopback Example}, {Torrent Example}
84*/
85
86/*! \fn void QTcpServer::newConnection()
87
88 This signal is emitted every time a new connection is available.
89
90 \sa hasPendingConnections(), nextPendingConnection()
91*/
92
93#include "private/qobject_p.h"
94#include "qalgorithms.h"
95#include "qhostaddress.h"
96#include "qlist.h"
97#include "qpointer.h"
98#include "qnativesocketengine_p.h"
99#include "qtcpserver.h"
100#include "qtcpsocket.h"
101#include "qnetworkproxy.h"
102
103QT_BEGIN_NAMESPACE
104
105#define Q_CHECK_SOCKETENGINE(returnValue) do { \
106 if (!d->socketEngine) { \
107 return returnValue; \
108 } } while (0)
109
110class QTcpServerPrivate : public QObjectPrivate, public QAbstractSocketEngineReceiver
111{
112 Q_DECLARE_PUBLIC(QTcpServer)
113public:
114 QTcpServerPrivate();
115 ~QTcpServerPrivate();
116
117 QList<QTcpSocket *> pendingConnections;
118
119 quint16 port;
120 QHostAddress address;
121
122 QAbstractSocket::SocketState state;
123 QAbstractSocketEngine *socketEngine;
124
125 QAbstractSocket::SocketError serverSocketError;
126 QString serverSocketErrorString;
127
128 int maxConnections;
129
130#ifndef QT_NO_NETWORKPROXY
131 QNetworkProxy proxy;
132 QNetworkProxy resolveProxy(const QHostAddress &address, quint16 port);
133#endif
134
135 // from QAbstractSocketEngineReceiver
136 void readNotification();
137 inline void writeNotification() {}
138 inline void exceptionNotification() {}
139 inline void connectionNotification() {}
140#ifndef QT_NO_NETWORKPROXY
141 inline void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *) {}
142#endif
143
144};
145
146/*! \internal
147*/
148QTcpServerPrivate::QTcpServerPrivate()
149 : port(0)
150 , state(QAbstractSocket::UnconnectedState)
151 , socketEngine(0)
152 , serverSocketError(QAbstractSocket::UnknownSocketError)
153 , maxConnections(30)
154{
155}
156
157/*! \internal
158*/
159QTcpServerPrivate::~QTcpServerPrivate()
160{
161}
162
163#ifndef QT_NO_NETWORKPROXY
164/*! \internal
165
166 Resolve the proxy to its final value.
167*/
168QNetworkProxy QTcpServerPrivate::resolveProxy(const QHostAddress &address, quint16 port)
169{
170 if (address == QHostAddress::LocalHost ||
171 address == QHostAddress::LocalHostIPv6)
172 return QNetworkProxy::NoProxy;
173
174 QList<QNetworkProxy> proxies;
175 if (proxy.type() != QNetworkProxy::DefaultProxy) {
176 // a non-default proxy was set with setProxy
177 proxies << proxy;
178 } else {
179 // try the application settings instead
180 QNetworkProxyQuery query(port, QString(), QNetworkProxyQuery::TcpServer);
181 proxies = QNetworkProxyFactory::proxyForQuery(query);
182 }
183
184 // return the first that we can use
185 foreach (const QNetworkProxy &p, proxies) {
186 if (p.capabilities() & QNetworkProxy::ListeningCapability)
187 return p;
188 }
189
190 // no proxy found
191 // DefaultProxy will raise an error
192 return QNetworkProxy(QNetworkProxy::DefaultProxy);
193}
194#endif
195
196/*! \internal
197*/
198void QTcpServerPrivate::readNotification()
199{
200 Q_Q(QTcpServer);
201 for (;;) {
202 if (pendingConnections.count() >= maxConnections) {
203#if defined (QTCPSERVER_DEBUG)
204 qDebug("QTcpServerPrivate::_q_processIncomingConnection() too many connections");
205#endif
206 if (socketEngine->isReadNotificationEnabled())
207 socketEngine->setReadNotificationEnabled(false);
208 return;
209 }
210
211 int descriptor = socketEngine->accept();
212 if (descriptor == -1)
213 break;
214#if defined (QTCPSERVER_DEBUG)
215 qDebug("QTcpServerPrivate::_q_processIncomingConnection() accepted socket %i", descriptor);
216#endif
217 q->incomingConnection(descriptor);
218
219 QPointer<QTcpServer> that = q;
220 emit q->newConnection();
221 if (!that || !q->isListening())
222 return;
223 }
224}
225
226/*!
227 Constructs a QTcpServer object.
228
229 \a parent is passed to the QObject constructor.
230
231 \sa listen(), setSocketDescriptor()
232*/
233QTcpServer::QTcpServer(QObject *parent)
234 : QObject(*new QTcpServerPrivate, parent)
235{
236}
237
238/*!
239 Destroys the QTcpServer object. If the server is listening for
240 connections, the socket is automatically closed.
241
242 Any client \l{QTcpSocket}s that are still connected must either
243 disconnect or be reparented before the server is deleted.
244
245 \sa close()
246*/
247QTcpServer::~QTcpServer()
248{
249 close();
250}
251
252/*!
253 Tells the server to listen for incoming connections on address \a
254 address and port \a port. If \a port is 0, a port is chosen
255 automatically. If \a address is QHostAddress::Any, the server
256 will listen on all network interfaces.
257
258 Returns true on success; otherwise returns false.
259
260 \sa isListening()
261*/
262bool QTcpServer::listen(const QHostAddress &address, quint16 port)
263{
264 Q_D(QTcpServer);