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

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

trunk: Merged in qt 4.6.2 sources.

File size: 15.7 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 \sa QTcpSocket
90*/
91
92/*! \enum QUdpSocket::BindFlag
93 \since 4.1
94
95 This enum describes the different flags you can pass to modify the
96 behavior of QUdpSocket::bind().
97
98 \note On Symbian OS bind flags behaviour depends on process capabilties.
99 If process has NetworkControl capability, the bind attempt with
100 ReuseAddressHint will always succeed even if the address and port is already
101 bound by another socket with any flags. If process does not have
102 NetworkControl capability, the bind attempt to address and port already
103 bound by another socket will always fail.
104
105 \value ShareAddress Allow other services to bind to the same address
106 and port. This is useful when multiple processes share
107 the load of a single service by listening to the same address and port
108 (e.g., a web server with several pre-forked listeners can greatly
109 improve response time). However, because any service is allowed to
110 rebind, this option is subject to certain security considerations.
111 Note that by combining this option with ReuseAddressHint, you will
112 also allow your service to rebind an existing shared address. On
113 Unix, this is equivalent to the SO_REUSEADDR socket option. On Windows,
114 this option is ignored.
115
116 \value DontShareAddress Bind the address and port exclusively, so that
117 no other services are allowed to rebind. By passing this option to
118 QUdpSocket::bind(), you are guaranteed that on successs, your service
119 is the only one that listens to the address and port. No services are
120 allowed to rebind, even if they pass ReuseAddressHint. This option
121 provides more security than ShareAddress, but on certain operating
122 systems, it requires you to run the server with administrator privileges.
123 On Unix and Mac OS X, not sharing is the default behavior for binding
124 an address and port, so this option is ignored. On Windows, this
125 option uses the SO_EXCLUSIVEADDRUSE socket option.
126
127 \value ReuseAddressHint Provides a hint to QUdpSocket that it should try
128 to rebind the service even if the address and port are already bound by
129 another socket. On Windows, this is equivalent to the SO_REUSEADDR
130 socket option. On Unix, this option is ignored.
131
132 \value DefaultForPlatform The default option for the current platform.
133 On Unix and Mac OS X, this is equivalent to (DontShareAddress
134 + ReuseAddressHint), and on Windows, its equivalent to ShareAddress.
135*/
136
137#include "qhostaddress.h"
138#include "qabstractsocket_p.h"
139#include "qudpsocket.h"
140
141QT_BEGIN_NAMESPACE
142
143#ifndef QT_NO_UDPSOCKET
144
145#define QT_CHECK_BOUND(function, a) do { \
146 if (!isValid()) { \
147 qWarning(function" called on a QUdpSocket when not in QUdpSocket::BoundState"); \
148 return (a); \
149 } } while (0)
150
151class QUdpSocketPrivate : public QAbstractSocketPrivate
152{
153 Q_DECLARE_PUBLIC(QUdpSocket)
154
155 bool doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
156 const QHostAddress &remoteAddress);
157public:
158 inline bool ensureInitialized(const QHostAddress &bindAddress, quint16 bindPort)
159 { return doEnsureInitialized(bindAddress, bindPort, QHostAddress()); }
160
161 inline bool ensureInitialized(const QHostAddress &remoteAddress)
162 { return doEnsureInitialized(QHostAddress(), 0, remoteAddress); }
163};
164
165bool QUdpSocketPrivate::doEnsureInitialized(const QHostAddress &bindAddress, quint16 bindPort,
166 const QHostAddress &remoteAddress)
167{
168 const QHostAddress *address = &bindAddress;
169 QAbstractSocket::NetworkLayerProtocol proto = address->protocol();
170 if (proto == QUdpSocket::UnknownNetworkLayerProtocol) {
171 address = &remoteAddress;
172 proto = address->protocol();
173 }
174
175#if defined(QT_NO_IPV6)
176 Q_Q(QUdpSocket);
177 if (proto == QUdpSocket::IPv6Protocol) {
178 socketError = QUdpSocket::UnsupportedSocketOperationError;
179 q->setErrorString(QUdpSocket::tr("This platform does not support IPv6"));
180 return false;
181 }
182#endif
183
184 // now check if the socket engine is initialized and to the right type
185 if (!socketEngine || !socketEngine->isValid() || socketEngine->protocol() != proto) {
186 resolveProxy(remoteAddress.toString(), bindPort);
187 if (!initSocketLayer(address->protocol()))
188 return false;
189 }
190
191 return true;
192}
193
194/*!
195 Creates a QUdpSocket object.
196
197 \a parent is passed to the QObject constructor.
198
199 \sa socketType()
200*/
201QUdpSocket::QUdpSocket(QObject *parent)
202 : QAbstractSocket(UdpSocket, *new QUdpSocketPrivate, parent)
203{
204 d_func()->isBuffered = false;
205}
206
207/*!
208 Destroys the socket, closing the connection if necessary.
209
210 \sa close()
211*/
212QUdpSocket::~QUdpSocket()
213{
214}
215
216/*!
217 Binds this socket to the address \a address and the port \a port.
218 When bound, the signal readyRead() is emitted whenever a UDP
219 datagram arrives on the specified address and port. This function
220 is useful to write UDP servers.
221
222 On success, the functions returns true and the socket enters
223 BoundState; otherwise it returns false.
224
225 The socket is bound using the DefaultForPlatform BindMode.
226
227 \sa readDatagram()
228*/
229bool QUdpSocket::bind(const QHostAddress &address, quint16 port)
230{
231 Q_D(QUdpSocket);
232 if (!d->ensureInitialized(address, port))
233 return false;
234
235 bool result = d_func()->socketEngine->bind(address, port);
236 d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
237
238 if (!result) {
239 d->socketError = d_func()->socketEngine->error();
240 setErrorString(d_func()->socketEngine->errorString());
241 emit error(d_func()->socketError);
242 return false;
243 }
244
245 d->state = BoundState;
246 d->localAddress = d->socketEngine->localAddress();
247 d->localPort = d->socketEngine->localPort();
248
249 emit stateChanged(d_func()->state);
250 d_func()->socketEngine->setReadNotificationEnabled(true);
251 return true;
252}
253
254/*!
255 \since 4.1
256 \overload
257
258 Binds to \a address on port \a port, using the BindMode \a mode.
259*/
260bool QUdpSocket::bind(const QHostAddress &address, quint16 port, BindMode mode)
261{
262 Q_D(QUdpSocket);
263 if (!d->ensureInitialized(address, port))
264 return false;
265
266#ifdef Q_OS_UNIX
267 if ((mode & ShareAddress) || (mode & ReuseAddressHint))
268 d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
269 else
270 d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
271#endif
272#ifdef Q_OS_WIN
273 if (mode & ReuseAddressHint)
274 d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
275 else
276 d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
277 if (mode & DontShareAddress)
278 d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 1);
279 else
280 d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 0);
281#endif
282 bool result = d_func()->socketEngine->bind(address, port);
283 d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
284
285 if (!result) {
286 d->socketError = d_func()->socketEngine->error();
287 setErrorString(d_func()->socketEngine->errorString());
288 emit error(d_func()->socketError);
289 return false;
290 }
291
292 d->state = BoundState;
293 d->localAddress = d->socketEngine->localAddress();
294 d->localPort = d->socketEngine->localPort();
295
296 emit stateChanged(d_func()->state);
297 d_func()->socketEngine->setReadNotificationEnabled(true);
298 return true;
299}
300
301/*! \overload
302
303 Binds to QHostAddress:Any on port \a port.
304*/
305bool QUdpSocket::bind(quint16 port)
306{
307 return bind(QHostAddress::Any, port);
308}
309
310/*!
311 \since 4.1
312 \overload
313
314 Binds to QHostAddress:Any on port \a port, using the BindMode \a mode.
315*/
316bool QUdpSocket::bind(quint16 port, BindMode mode)
317{
318 return bind(QHostAddress::Any, port, mode);
319}
320
321/*!
322 Returns true if at least one datagram is waiting to be read;
323 otherwise returns false.
324
325 \sa pendingDatagramSize(), readDatagram()
326*/
327bool QUdpSocket::hasPendingDatagrams() const
328{
329 QT_CHECK_BOUND("QUdpSocket::hasPendingDatagrams()", false);
330 return d_func()->socketEngine->hasPendingDatagrams();
331}
332
333/*!
334 Returns the size of the first pending UDP datagram. If there is
335 no datagram available, this function returns -1.
336
337 \sa hasPendingDatagrams(), readDatagram()
338*/
339qint64 QUdpSocket::pendingDatagramSize() const
340{
341 QT_CHECK_BOUND("QUdpSocket::pendingDatagramSize()", -1);
342 return d_func()->socketEngine->pendingDatagramSize();
343}
344
345/*!
346 Sends the datagram at \a data of size \a size to the host
347 address \a address at port \a port. Returns the number of
348 bytes sent on success; otherwise returns -1.
349
350 Datagrams are always written as one block. The maximum size of a
351 datagram is highly platform-dependent, but can be as low as 8192
352 bytes. If the datagram is too large, this function will return -1
353 and error() will return DatagramTooLargeError.
354
355 Sending datagrams larger than 512 bytes is in general disadvised,
356 as even if they are sent successfully, they are likely to be
357 fragmented by the IP layer before arriving at their final
358 destination.
359
360 \warning In S60 5.0 and earlier versions, the writeDatagram return
361 value is not reliable for large datagrams.
362
363 \warning Calling this function on a connected UDP socket may
364 result in an error and no packet being sent. If you are using a
365 connected socket, use write() to send datagrams.
366
367 \sa readDatagram(), write()
368*/
369qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address,
370 quint16 port)
371{
372 Q_D(QUdpSocket);
373#if defined QUDPSOCKET_DEBUG
374 qDebug("QUdpSocket::writeDatagram(%p, %llu, \"%s\", %i)", data, size,
375 address.toString().toLatin1().constData(), port);
376#endif
377 if (!d->ensureInitialized(address))
378 return -1;
379
380 qint64 sent = d->socketEngine->writeDatagram(data, size, address, port);
381#ifdef Q_OS_SYMBIAN
382 if( QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0 ) {
383 // This is evil hack, but for some reason native RSocket::SendTo returns 0,
384 // for large datagrams (such as 600 bytes). Based on comments from Open C team
385 // this should happen only in platforms <= S60 5.0.
386 // As an workaround, we just set sent = size
387 if( sent == 0 )
388 sent = size;
389 }
390#endif
391 d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
392
393 if (sent >= 0) {
394 emit bytesWritten(sent);
395 } else {
396 d->socketError = d->socketEngine->error();
397 setErrorString(d->socketEngine->errorString());
398 emit error(d->socketError);
399 }
400 return sent;
401}
402
403/*!
404 \fn qint64 QUdpSocket::writeDatagram(const QByteArray &datagram,
405 const QHostAddress &host, quint16 port)
406 \overload
407
408 Sends the datagram \a datagram to the host address \a host and at
409 port \a port.
410*/
411
412/*!
413 Receives a datagram no larger than \a maxSize bytes and stores
414 it in \a data. The sender's host address and port is stored in
415 *\a address and *\a port (unless the pointers are 0).
416
417 Returns the size of the datagram on success; otherwise returns
418 -1.
419
420 If \a maxSize is too small, the rest of the datagram will be
421 lost. To avoid loss of data, call pendingDatagramSize() to
422 determine the size of the pending datagram before attempting to
423 read it. If \a maxSize is 0, the datagram will be discarded.
424
425 \sa writeDatagram(), hasPendingDatagrams(), pendingDatagramSize()
426*/
427qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address,
428 quint16 *port)
429{
430 Q_D(QUdpSocket);
431
432#if defined QUDPSOCKET_DEBUG
433 qDebug("QUdpSocket::readDatagram(%p, %llu, %p, %p)", data, maxSize, address, port);
434#endif
435 QT_CHECK_BOUND("QUdpSocket::readDatagram()", -1);
436 qint64 readBytes = d->socketEngine->readDatagram(data, maxSize, address, port);
437 d_func()->socketEngine->setReadNotificationEnabled(true);
438 if (readBytes < 0) {
439 d->socketError = d->socketEngine->error();
440 setErrorString(d->socketEngine->errorString());
441 emit error(d->socketError);
442 }
443 return readBytes;
444}
445#endif // QT_NO_UDPSOCKET
446
447QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.