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

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

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

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