source: trunk/src/network/socket/qudpsocket.cpp@ 788

Last change on this file since 788 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 16.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** 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 have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42//#define QUDPSOCKET_DEBUG
43
44/*! \class QUdpSocket
45
46 \reentrant
47 \brief The QUdpSocket class provides a UDP socket.
48
49 \ingroup network
50 \inmodule QtNetwork
51
52 UDP (User Datagram Protocol) is a lightweight, unreliable,
53 datagram-oriented, connectionless protocol. It can be used when
54 reliability isn't important. QUdpSocket is a subclass of
55 QAbstractSocket that allows you to send and receive UDP
56 datagrams.
57
58 The most common way to use this class is to bind to an address and port
59 using bind(), then call writeDatagram() and readDatagram() to transfer
60 data. If you want to use the standard QIODevice functions read(),
61 readLine(), write(), etc., you must first connect the socket directly to a
62 peer by calling connectToHost().
63
64 The socket emits the bytesWritten() signal every time a datagram
65 is written to the network. If you just want to send datagrams,
66 you don't need to call bind().
67
68 The readyRead() signal is emitted whenever datagrams arrive. In
69 that case, hasPendingDatagrams() returns true. Call
70 pendingDatagramSize() to obtain the size of the first pending
71 datagram, and readDatagram() to read it.
72
73 \note An incoming datagram should be read when you receive the readyRead()
74 signal, otherwise this signal will not be emitted for the next datagram.
75
76 Example:
77
78 \snippet doc/src/snippets/code/src_network_socket_qudpsocket.cpp 0
79
80 With QUdpSocket, you can also establish a virtual connection to a
81 UDP server using connectToHost() and then use read() and write()
82 to exchange datagrams without specifying the receiver for each
83 datagram.
84
85 The \l{network/broadcastsender}{Broadcast Sender} and
86 \l{network/broadcastreceiver}{Broadcast Receiver} examples
87 illustrate how to use QUdpSocket in applications.
88
89 \section1 Symbian Platform Security Requirements
90
91 On Symbian, processes which use this class must have the
92 \c NetworkServices platform security capability. If the client
93 process lacks this capability, operations will result in a panic.
94
95 Platform security capabilities are added via the
96 \l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY}
97 qmake variable.
98
99 \sa QTcpSocket
100*/
101
102/*! \enum QUdpSocket::BindFlag
103 \since 4.1
104
105 This enum describes the different flags you can pass to modify the
106 behavior of QUdpSocket::bind().
107
108 \note On Symbian OS bind flags behaviour depends on process capabilties.
109 If process has NetworkControl capability, the bind attempt with
110 ReuseAddressHint will always succeed even if the address and port is already
111 bound by another socket with any flags. If process does not have
112 NetworkControl capability, the bind attempt to address and port already
113 bound by another socket will always fail.
114
115 \value ShareAddress Allow other services to bind to the same address
116 and port. This is useful when multiple processes share
117 the load of a single service by listening to the same address and port
118 (e.g., a web server with several pre-forked listeners can greatly
119 improve response time). However, because any service is allowed to
120 rebind, this option is subject to certain security considerations.
121 Note that by combining this option with ReuseAddressHint, you will
122 also allow your service to rebind an existing shared address. On
123 Unix, this is equivalent to the SO_REUSEADDR socket option. On Windows,
124 this option is ignored.
125
126 \value DontShareAddress Bind the address and port exclusively, so that
127 no other services are allowed to rebind. By passing this option to
128 QUdpSocket::bind(), you are guaranteed that on successs, your service
129 is the only one that listens to the address and port. No services are
130 allowed to rebind, even if they pass ReuseAddressHint. This option
131 provides more security than ShareAddress, but on certain operating
132 systems, it requires you to run the server with administrator privileges.
133 On Unix and Mac OS X, not sharing is the default behavior for binding
134 an address and port, so this option is ignored. On Windows, this
135 option uses the SO_EXCLUSIVEADDRUSE socket option.
136
137 \value ReuseAddressHint Provides a hint to QUdpSocket that it should try
138 to rebind the service even if the address and port are already bound by
139 another socket. On Windows, this is equivalent to the SO_REUSEADDR
140 socket option. On Unix, this option is ignored.
141
142 \value DefaultForPlatform The default option for the current platform.
143 On Unix and Mac OS X, this is equivalent to (DontShareAddress
144 + ReuseAddressHint), and on Windows, its equivalent to ShareAddress.
145*/
146
147#include "qhostaddress.h"
148#include "qabstractsocket_p.h"
149#include "qudpsocket.h"
150
151QT_BEGIN_NAMESPACE
152
153#ifndef QT_NO_UDPSOCKET
154
155#define QT_CHECK_BOUND(function, a) do { \
156 if (!isValid()) { \
157 qWarning(function" called on a QUdpSocket when not in QUdpSocket::BoundState"); \
158 return (a); \
159 } } while (0)
160
161class QUdpSocketPrivate : public QAbstractSocketPrivate
162{
163 Q_DECLARE_PUBLIC(QUdpSocket)
164
165 bool doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
166 const QHostAddress &remoteAddress);
167public:
168 inline bool ensureInitialized(const QHostAddress &bindAddress, quint16 bindPort)
169 { return doEnsureInitialized(bindAddress, bindPort, QHostAddress()); }
170
171 inline bool ensureInitialized(const QHostAddress &remoteAddress)
172 { return doEnsureInitialized(QHostAddress(), 0, remoteAddress); }
173};
174
175bool QUdpSocketPrivate::doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
176 const QHostAddress &remoteAddress)
177{
178 const QHostAddress *address = &bindAddress;
179 QAbstractSocket::NetworkLayerProtocol proto = address->protocol();
180 if (proto == QUdpSocket::UnknownNetworkLayerProtocol) {
181 address = &remoteAddress;
182 proto = address->protocol();
183 }
184
185#if defined(QT_NO_IPV6)
186 Q_Q(QUdpSocket);
187 if (proto == QUdpSocket::IPv6Protocol) {
188 socketError = QUdpSocket::UnsupportedSocketOperationError;
189 q->setErrorString(QUdpSocket::tr("This platform does not support IPv6"));
190 return false;
191 }
192#endif
193
194 // now check if the socket engine is initialized and to the right type
195 if (!socketEngine || !socketEngine->isValid() || socketEngine->protocol() != proto) {
196 resolveProxy(remoteAddress.toString(), bindPort);
197 if (!initSocketLayer(address->protocol()))
198 return false;
199 }
200
201 return true;
202}
203
204/*!
205 Creates a QUdpSocket object.
206
207 \a parent is passed to the QObject constructor.
208
209 \sa socketType()
210*/
211QUdpSocket::QUdpSocket(QObject *parent)
212 : QAbstractSocket(UdpSocket, *new QUdpSocketPrivate, parent)
213{
214 d_func()->isBuffered = false;
215}
216
217/*!
218 Destroys the socket, closing the connection if necessary.
219
220 \sa close()
221*/
222QUdpSocket::~QUdpSocket()
223{
224}
225
226/*!
227 Binds this socket to the address \a address and the port \a port.
228 When bound, the signal readyRead() is emitted whenever a UDP
229 datagram arrives on the specified address and port. This function
230 is useful to write UDP servers.
231
232 On success, the functions returns true and the socket enters
233 BoundState; otherwise it returns false.
234
235 The socket is bound using the DefaultForPlatform BindMode.
236
237 \sa readDatagram()
238*/
239bool QUdpSocket::bind(const QHostAddress &address, quint16 port)
240{
241 Q_D(QUdpSocket);
242 if (!d->ensureInitialized(address, port))
243 return false;
244
245 bool result = d_func()->socketEngine->bind(address, port);
246 d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
247
248 if (!result) {
249 d->socketError = d_func()->socketEngine->error();
250 setErrorString(d_func()->socketEngine->errorString());
251 emit error(d_func()->socketError);
252 return false;
253 }
254
255 d->state = BoundState;
256 d->localAddress = d->socketEngine->localAddress();
257 d->localPort = d->socketEngine->localPort();
258
259 emit stateChanged(d_func()->state);
260 d_func()->socketEngine->setReadNotificationEnabled(true);
261 return true;
262}
263
264/*!
265 \since 4.1
266 \overload
267
268 Binds to \a address on port \a port, using the BindMode \a mode.
269*/
270bool QUdpSocket::bind(const QHostAddress &address, quint16 port, BindMode mode)
271{
272 Q_D(QUdpSocket);
273 if (!d->ensureInitialized(address, port))
274 return false;
275
276#ifdef Q_OS_UNIX
277 if ((mode & ShareAddress) || (mode & ReuseAddressHint))
278 d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
279 else
280 d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
281#endif
282#ifdef Q_OS_WIN
283 if (mode & ReuseAddressHint)
284 d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
285 else
286 d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
287 if (mode & DontShareAddress)
288 d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 1);
289 else
290 d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 0);
291#endif
292 bool result = d_func()->socketEngine->bind(address, port);
293 d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
294
295 if (!result) {
296 d->socketError = d_func()->socketEngine->error();
297 setErrorString(d_func()->socketEngine->errorString());
298 emit error(d_func()->socketError);
299 return false;
300 }
301
302 d->state = BoundState;
303 d->localAddress = d->socketEngine->localAddress();
304 d->localPort = d->socketEngine->localPort();
305
306 emit stateChanged(d_func()->state);
307 d_func()->socketEngine->setReadNotificationEnabled(true);
308 return true;
309}
310
311/*! \overload
312
313 Binds to QHostAddress:Any on port \a port.
314*/
315bool QUdpSocket::bind(quint16 port)
316{
317 return bind(QHostAddress::Any, port);
318}
319
320/*!
321 \since 4.1
322 \overload
323
324 Binds to QHostAddress:Any on port \a port, using the BindMode \a mode.
325*/
326bool QUdpSocket::bind(quint16 port, BindMode mode)
327{
328 return bind(QHostAddress::Any, port, mode);
329}
330
331/*!
332 Returns true if at least one datagram is waiting to be read;
333 otherwise returns false.
334
335 \sa pendingDatagramSize(), readDatagram()
336*/
337bool QUdpSocket::hasPendingDatagrams() const
338{
339 QT_CHECK_BOUND("QUdpSocket::hasPendingDatagrams()", false);
340 return d_func()->socketEngine->hasPendingDatagrams();
341}
342
343/*!
344 Returns the size of the first pending UDP datagram. If there is
345 no datagram available, this function returns -1.
346
347 \sa hasPendingDatagrams(), readDatagram()
348*/
349qint64 QUdpSocket::pendingDatagramSize() const
350{
351 QT_CHECK_BOUND("QUdpSocket::pendingDatagramSize()", -1);
352 return d_func()->socketEngine->pendingDatagramSize();
353}
354
355/*!
356 Sends the datagram at \a data of size \a size to the host
357 address \a address at port \a port. Returns the number of
358 bytes sent on success; otherwise returns -1.
359
360 Datagrams are always written as one block. The maximum size of a
361 datagram is highly platform-dependent, but can be as low as 8192
362 bytes. If the datagram is too large, this function will return -1
363 and error() will return DatagramTooLargeError.
364
365 Sending datagrams larger than 512 bytes is in general disadvised,
366 as even if they are sent successfully, they are likely to be
367 fragmented by the IP layer before arriving at their final
368 destination.
369
370 \warning In S60 5.0 and earlier versions, the writeDatagram return
371 value is not reliable for large datagrams.
372
373 \warning Calling this function on a connected UDP socket may
374 result in an error and no packet being sent. If you are using a
375 connected socket, use write() to send datagrams.
376
377 \sa readDatagram(), write()
378*/
379qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address,
380 quint16 port)
381{
382 Q_D(QUdpSocket);
383#if defined QUDPSOCKET_DEBUG
384 qDebug("QUdpSocket::writeDatagram(%p, %llu, \"%s\", %i)", data, size,
385 address.toString().toLatin1().constData(), port);
386#endif
387 if (!d->ensureInitialized(address))
388 return -1;
389
390 qint64 sent = d->socketEngine->writeDatagram(data, size, address, port);
391#ifdef Q_OS_SYMBIAN
392 if( QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0 ) {
393 // This is evil hack, but for some reason native RSocket::SendTo returns 0,
394 // for large datagrams (such as 600 bytes). Based on comments from Open C team
395 // this should happen only in platforms <= S60 5.0.
396 // As an workaround, we just set sent = size
397 if( sent == 0 )
398 sent = size;
399 }
400#endif
401 d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
402
403 if (sent >= 0) {
404 emit bytesWritten(sent);
405 } else {
406 d->socketError = d->socketEngine->error();
407 setErrorString(d->socketEngine->errorString());
408 emit error(d->socketError);
409 }
410 return sent;
411}
412
413/*!
414 \fn qint64 QUdpSocket::writeDatagram(const QByteArray &datagram,
415 const QHostAddress &host, quint16 port)
416 \overload
417
418 Sends the datagram \a datagram to the host address \a host and at
419 port \a port.
420*/
421
422/*!
423 Receives a datagram no larger than \a maxSize bytes and stores
424 it in \a data. The sender's host address and port is stored in
425 *\a address and *\a port (unless the pointers are 0).
426
427 Returns the size of the datagram on success; otherwise returns
428 -1.
429
430 If \a maxSize is too small, the rest of the datagram will be
431 lost. To avoid loss of data, call pendingDatagramSize() to
432 determine the size of the pending datagram before attempting to
433 read it. If \a maxSize is 0, the datagram will be discarded.
434
435 \sa writeDatagram(), hasPendingDatagrams(), pendingDatagramSize()
436*/
437qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address,
438 quint16 *port)
439{
440 Q_D(QUdpSocket);
441
442#if defined QUDPSOCKET_DEBUG
443 qDebug("QUdpSocket::readDatagram(%p, %llu, %p, %p)", data, maxSize, address, port);
444#endif
445 QT_CHECK_BOUND("QUdpSocket::readDatagram()", -1);
446 qint64 readBytes = d->socketEngine->readDatagram(data, maxSize, address, port);
447 d_func()->socketEngine->setReadNotificationEnabled(true);
448 if (readBytes < 0) {
449 d->socketError = d->socketEngine->error();
450 setErrorString(d->socketEngine->errorString());
451 emit error(d->socketError);
452 }
453 return readBytes;
454}
455#endif // QT_NO_UDPSOCKET
456
457QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.