diff options
Diffstat (limited to 'src/qt3support/network/q3socketdevice.cpp')
-rw-r--r-- | src/qt3support/network/q3socketdevice.cpp | 757 |
1 files changed, 757 insertions, 0 deletions
diff --git a/src/qt3support/network/q3socketdevice.cpp b/src/qt3support/network/q3socketdevice.cpp new file mode 100644 index 0000000..7e53163 --- /dev/null +++ b/src/qt3support/network/q3socketdevice.cpp @@ -0,0 +1,757 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt3Support module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "q3socketdevice.h" +#ifndef QT_NO_NETWORK + +#include "qwindowdefs.h" +#include <string.h> + +QT_BEGIN_NAMESPACE + +//#define Q3SOCKETDEVICE_DEBUG + + +class Q3SocketDevicePrivate +{ +public: + Q3SocketDevicePrivate( Q3SocketDevice::Protocol p ) + : protocol(p) + { } + + Q3SocketDevice::Protocol protocol; +}; + + +/*! + \class Q3SocketDevice + \brief The Q3SocketDevice class provides a platform-independent low-level socket API. + + \compat + \reentrant + + This class provides a low level API for working with sockets. Users of + this class are assumed to have networking experience. For most users the + Q3Socket class provides a much easier and high level alternative, but + certain things (like UDP) can't be done with Q3Socket and if you need a + platform-independent API for those, Q3SocketDevice is the right choice. + + The essential purpose of the class is to provide a QIODevice that + works on sockets, wrapped in a platform-independent API. + + When calling connect() or bind(), Q3SocketDevice detects the + protocol family (IPv4, IPv6) automatically. Passing the protocol + family to Q3SocketDevice's constructor or to setSocket() forces + creation of a socket device of a specific protocol. If not set, the + protocol will be detected at the first call to connect() or bind(). + + \sa Q3Socket, QSocketNotifier, QHostAddress +*/ + + +/*! + \enum Q3SocketDevice::Protocol + + This enum type describes the protocol family of the socket. Possible values + are: + + \value IPv4 The socket is an IPv4 socket. + \value IPv6 The socket is an IPv6 socket. + \value Unknown The protocol family of the socket is not known. This can + happen if you use Q3SocketDevice with an already existing socket; it + tries to determine the protocol family, but this can fail if the + protocol family is not known to Q3SocketDevice. + + \sa protocol() setSocket() +*/ + +/*! + \enum Q3SocketDevice::Error + + This enum type describes the error states of Q3SocketDevice. + + \value NoError No error has occurred. + + \value AlreadyBound The device is already bound, according to bind(). + + \value Inaccessible The operating system or firewall prohibited + the action. + + \value NoResources The operating system ran out of a resource. + + \value InternalError An internal error occurred in Q3SocketDevice. + + \value Impossible An attempt was made to do something which makes + no sense. For example: + \snippet doc/src/snippets/code/src_qt3support_network_q3socketdevice.cpp 0 + The libc ::close() closes the socket, but Q3SocketDevice is not aware + of this. So when you call writeBlock(), the impossible happens. + + \value NoFiles The operating system will not let Q3SocketDevice open + another file. + + \value ConnectionRefused A connection attempt was rejected by the + peer. + + \value NetworkFailure There is a network failure. + + \value UnknownError The operating system did something + unexpected. + + \omitvalue Bug +*/ + +/*! + \enum Q3SocketDevice::Type + + This enum type describes the type of the socket: + \value Stream a stream socket (TCP, usually) + \value Datagram a datagram socket (UDP, usually) +*/ + + +/*! + Creates a Q3SocketDevice object for the existing socket \a socket. + + The \a type argument must match the actual socket type; use \c + Q3SocketDevice::Stream for a reliable, connection-oriented TCP + socket, or Q3SocketDevice::Datagram for an unreliable, + connectionless UDP socket. +*/ +Q3SocketDevice::Q3SocketDevice( int socket, Type type ) + : fd( socket ), t( type ), p( 0 ), pp( 0 ), e( NoError ), + d(new Q3SocketDevicePrivate(Unknown)) +{ +#if defined(Q3SOCKETDEVICE_DEBUG) + qDebug( "Q3SocketDevice: Created Q3SocketDevice %p (socket %x, type %d)", + this, socket, type ); +#endif + init(); + setSocket( socket, type ); +} + +/*! + Creates a Q3SocketDevice object for a stream or datagram socket. + + The \a type argument must be either Q3SocketDevice::Stream for a + reliable, connection-oriented TCP socket, or \c + Q3SocketDevice::Datagram for an unreliable UDP socket. + + The socket is created as an IPv4 socket. + + \sa blocking() protocol() +*/ +Q3SocketDevice::Q3SocketDevice( Type type ) + : fd( -1 ), t( type ), p( 0 ), pp( 0 ), e( NoError ), + d(new Q3SocketDevicePrivate(IPv4)) +{ +#if defined(Q3SOCKETDEVICE_DEBUG) + qDebug( "Q3SocketDevice: Created Q3SocketDevice object %p, type %d", + this, type ); +#endif + init(); + setSocket( createNewSocket(), type ); +} + +/*! + Creates a Q3SocketDevice object for a stream or datagram socket. + + The \a type argument must be either Q3SocketDevice::Stream for a + reliable, connection-oriented TCP socket, or \c + Q3SocketDevice::Datagram for an unreliable UDP socket. + + The \a protocol indicates whether the socket should be of type IPv4 + or IPv6. Passing \c Unknown is not meaningful in this context and you + should avoid using (it creates an IPv4 socket, but your code is not easily + readable). + + The argument \a dummy is necessary for compatibility with some + compilers. + + \sa blocking() protocol() +*/ +Q3SocketDevice::Q3SocketDevice( Type type, Protocol protocol, int ) + : fd( -1 ), t( type ), p( 0 ), pp( 0 ), e( NoError ), + d(new Q3SocketDevicePrivate(protocol)) +{ +#if defined(Q3SOCKETDEVICE_DEBUG) + qDebug( "Q3SocketDevice: Created Q3SocketDevice object %p, type %d", + this, type ); +#endif + init(); + setSocket( createNewSocket(), type ); +} + +/*! + Destroys the socket device and closes the socket if it is open. +*/ +Q3SocketDevice::~Q3SocketDevice() +{ + close(); + delete d; + d = 0; +#if defined(Q3SOCKETDEVICE_DEBUG) + qDebug( "Q3SocketDevice: Destroyed Q3SocketDevice %p", this ); +#endif +} + + +/*! + Returns true if this is a valid socket; otherwise returns false. + + \sa socket() +*/ +bool Q3SocketDevice::isValid() const +{ + return fd != -1; +} + + +/*! + \fn Type Q3SocketDevice::type() const + + Returns the socket type which is either Q3SocketDevice::Stream + or Q3SocketDevice::Datagram. + + \sa socket() +*/ +Q3SocketDevice::Type Q3SocketDevice::type() const +{ + return t; +} + +/*! + Returns the socket's protocol family, which is one of \c Unknown, \c IPv4, + or \c IPv6. + + Q3SocketDevice either creates a socket with a well known protocol family or + it uses an already existing socket. In the first case, this function + returns the protocol family it was constructed with. In the second case, it + tries to determine the protocol family of the socket; if this fails, it + returns \c Unknown. + + \sa Protocol setSocket() +*/ +Q3SocketDevice::Protocol Q3SocketDevice::protocol() const +{ + if ( d->protocol == Unknown ) + d->protocol = getProtocol(); + return d->protocol; +} + +/*! + Returns the socket number, or -1 if it is an invalid socket. + + \sa isValid(), type() +*/ +int Q3SocketDevice::socket() const +{ + return fd; +} + + +/*! + Sets the socket device to operate on the existing socket \a + socket. + + The \a type argument must match the actual socket type; use \c + Q3SocketDevice::Stream for a reliable, connection-oriented TCP + socket, or Q3SocketDevice::Datagram for an unreliable, + connectionless UDP socket. + + Any existing socket is closed. + + \sa isValid(), close() +*/ +void Q3SocketDevice::setSocket( int socket, Type type ) +{ + if ( fd != -1 ) // close any open socket + close(); +#if defined(Q3SOCKETDEVICE_DEBUG) + qDebug( "Q3SocketDevice::setSocket: socket %x, type %d", socket, type ); +#endif + t = type; + fd = socket; + d->protocol = Unknown; + e = NoError; + resetStatus(); + open( ReadWrite ); + fetchConnectionParameters(); +} + + +/*! + Opens the socket using the specified QIODevice file \a mode. This + function is called from the Q3SocketDevice constructors and from + the setSocket() function. You should not call it yourself. + + \sa close() +*/ +bool Q3SocketDevice::open( OpenMode mode ) +{ + if ( isOpen() || !isValid() ) + return false; +#if defined(Q3SOCKETDEVICE_DEBUG) + qDebug( "Q3SocketDevice::open: mode %x", mode ); +#endif + setOpenMode( (mode & ReadWrite) | Unbuffered ); + return true; +} + +/*! + \fn bool Q3SocketDevice::open(int mode) + \overload +*/ +/*! + The current Q3SocketDevice implementation does not buffer at all, + so this is a no-op. This function always returns true. +*/ +bool Q3SocketDevice::flush() +{ + return true; +} + + +/*! + \reimp + + The size is meaningless for a socket, therefore this function returns 0. +*/ +QIODevice::Offset Q3SocketDevice::size() const +{ + return 0; +} + + +/*! + The read/write index is meaningless for a socket, therefore this + function returns 0. +*/ +QIODevice::Offset Q3SocketDevice::at() const +{ + return 0; +} + + +/*! + The read/write index is meaningless for a socket, therefore this + function does nothing and returns true. + + The \a offset parameter is ignored. +*/ +bool Q3SocketDevice::at( Offset /* offset */ ) +{ + return true; +} + + +/*! + \reimp + + Returns true if no data is currently available at the socket; + otherwise returns false. +*/ +bool Q3SocketDevice::atEnd() const +{ + return bytesAvailable() <= 0; +} + +/*! + Returns true if the address of this socket can be used by other + sockets at the same time, and false if this socket claims + exclusive ownership. + + \sa setAddressReusable() +*/ +bool Q3SocketDevice::addressReusable() const +{ + return option( ReuseAddress ); +} + + +/*! + Sets the address of this socket to be usable by other sockets too + if \a enable is true, and to be used exclusively by this socket if + \a enable is false. + + When a socket is reusable, other sockets can use the same port + number (and IP address), which is generally useful. Of course + other sockets cannot use the same + (address,port,peer-address,peer-port) 4-tuple as this socket, so + there is no risk of confusing the two TCP connections. + + \sa addressReusable() +*/ +void Q3SocketDevice::setAddressReusable( bool enable ) +{ + setOption( ReuseAddress, enable ); +} + + +/*! + Returns the size of the operating system receive buffer. + + \sa setReceiveBufferSize() +*/ +int Q3SocketDevice::receiveBufferSize() const +{ + return option( ReceiveBuffer ); +} + + +/*! + Sets the size of the operating system receive buffer to \a size. + + The operating system receive buffer size effectively limits two + things: how much data can be in transit at any one moment, and how + much data can be received in one iteration of the main event loop. + + The default is operating system-dependent. A socket that receives + large amounts of data is probably best with a buffer size of + 49152. +*/ +void Q3SocketDevice::setReceiveBufferSize( uint size ) +{ + setOption( ReceiveBuffer, size ); +} + + +/*! + Returns the size of the operating system send buffer. + + \sa setSendBufferSize() +*/ +int Q3SocketDevice::sendBufferSize() const +{ + return option( SendBuffer ); +} + + +/*! + Sets the size of the operating system send buffer to \a size. + + The operating system send buffer size effectively limits how much + data can be in transit at any one moment. + + The default is operating system-dependent. A socket that sends + large amounts of data is probably best with a buffer size of + 49152. +*/ +void Q3SocketDevice::setSendBufferSize( uint size ) +{ + setOption( SendBuffer, size ); +} + + +/*! + Returns the port number of this socket device. This may be 0 for a + while, but is set to something sensible as soon as a sensible + value is available. + + Note that Qt always uses native byte order, i.e. 67 is 67 in Qt; + there is no need to call htons(). +*/ +quint16 Q3SocketDevice::port() const +{ + return p; +} + + +/*! + Returns the address of this socket device. This may be 0.0.0.0 for + a while, but is set to something sensible as soon as a sensible + value is available. +*/ +QHostAddress Q3SocketDevice::address() const +{ + return a; +} + + +/*! + Returns the first error seen. +*/ +Q3SocketDevice::Error Q3SocketDevice::error() const +{ + return e; +} + + +/*! + Allows subclasses to set the error state to \a err. +*/ +void Q3SocketDevice::setError( Error err ) +{ + e = err; +} + +/*! \fn Q3SocketDevice::readBlock(char *data, Q_ULONG maxlen) + + Reads \a maxlen bytes from the socket into \a data and returns the + number of bytes read. Returns -1 if an error occurred. Returning 0 + is not an error. For Stream sockets, 0 is returned when the remote + host closes the connection. For Datagram sockets, 0 is a valid + datagram size. +*/ + +/*! \fn Q3SocketDevice::writeBlock(const char *data, Q_ULONG len) + + Writes \a len bytes to the socket from \a data and returns the + number of bytes written. Returns -1 if an error occurred. + + This is used for Q3SocketDevice::Stream sockets. +*/ + +/*! + \fn Q_LONG Q3SocketDevice::writeBlock( const char * data, Q_ULONG len, + const QHostAddress & host, Q_UINT16 port ) + \overload + + Writes \a len bytes to the socket from \a data and returns the + number of bytes written. Returns -1 if an error occurred. + + This is used for Q3SocketDevice::Datagram sockets. You must + specify the \a host and \a port of the destination of the data. +*/ + +/*! + \fn bool Q3SocketDevice::isSequential() const + \internal +*/ + +/*! + \fn qint64 Q3SocketDevice::readData( char *data, qint64 maxlen ) + + Reads \a maxlen bytes from the socket into \a data and returns the + number of bytes read. Returns -1 if an error occurred. +*/ + +/*! + \fn int Q3SocketDevice::createNewSocket() + + Creates a new socket identifier. Returns -1 if there is a failure + to create the new identifier; error() explains why. + + \sa setSocket() +*/ + +/*! + \fn void Q3SocketDevice::close() + \reimp + + Closes the socket and sets the socket identifier to -1 (invalid). + + (This function ignores errors; if there are any then a file + descriptor leakage might result. As far as we know, the only error + that can arise is EBADF, and that would of course not cause + leakage. There may be OS-specific errors that we haven't come + across, however.) + + \sa open() +*/ + +/*! + \fn bool Q3SocketDevice::blocking() const + + Returns true if the socket is valid and in blocking mode; + otherwise returns false. + + Note that this function does not set error(). + + \warning On Windows, this function always returns true since the + ioctlsocket() function is broken. + + \sa setBlocking(), isValid() +*/ + +/*! + \fn void Q3SocketDevice::setBlocking( bool enable ) + + Makes the socket blocking if \a enable is true or nonblocking if + \a enable is false. + + Sockets are blocking by default, but we recommend using + nonblocking socket operations, especially for GUI programs that + need to be responsive. + + \warning On Windows, this function should be used with care since + whenever you use a QSocketNotifier on Windows, the socket is + immediately made nonblocking. + + \sa blocking(), isValid() +*/ + +/*! + \fn int Q3SocketDevice::option( Option opt ) const + + Returns the value of the socket option \a opt. +*/ + +/*! + \fn void Q3SocketDevice::setOption( Option opt, int v ) + + Sets the socket option \a opt to \a v. +*/ + +/*! + \fn bool Q3SocketDevice::connect( const QHostAddress &addr, Q_UINT16 port ) + + Connects to the IP address and port specified by \a addr and \a + port. Returns true if it establishes a connection; otherwise returns false. + If it returns false, error() explains why. + + Note that error() commonly returns NoError for non-blocking + sockets; this just means that you can call connect() again in a + little while and it'll probably succeed. +*/ + +/*! + \fn bool Q3SocketDevice::bind( const QHostAddress &address, Q_UINT16 port ) + + Assigns a name to an unnamed socket. The name is the host address + \a address and the port number \a port. If the operation succeeds, + bind() returns true; otherwise it returns false without changing + what port() and address() return. + + bind() is used by servers for setting up incoming connections. + Call bind() before listen(). +*/ + +/*! + \fn bool Q3SocketDevice::listen( int backlog ) + + Specifies how many pending connections a server socket can have. + Returns true if the operation was successful; otherwise returns + false. A \a backlog value of 50 is quite common. + + The listen() call only applies to sockets where type() is \c + Stream, i.e. not to \c Datagram sockets. listen() must not be + called before bind() or after accept(). + + \sa bind(), accept() +*/ + +/*! + \fn int Q3SocketDevice::accept() + + Extracts the first connection from the queue of pending + connections for this socket and returns a new socket identifier. + Returns -1 if the operation failed. + + \sa bind(), listen() +*/ + +/*! + \fn qint64 Q3SocketDevice::bytesAvailable() const + + Returns the number of bytes available for reading, or -1 if an + error occurred. + + \warning On Microsoft Windows, we use the ioctlsocket() function + to determine the number of bytes queued on the socket. According + to Microsoft (KB Q125486), ioctlsocket() sometimes returns an + incorrect number. The only safe way to determine the amount of + data on the socket is to read it using readBlock(). QSocket has + workarounds to deal with this problem. +*/ + +/*! + \fn Q_LONG Q3SocketDevice::waitForMore( int msecs, bool *timeout ) const + + Wait up to \a msecs milliseconds for more data to be available. If + \a msecs is -1 the call will block indefinitely. + + Returns the number of bytes available for reading, or -1 if an + error occurred. + + If \a timeout is non-null and no error occurred (i.e. it does not + return -1): this function sets *\a timeout to true, if the reason + for returning was that the timeout was reached; otherwise it sets + *\a timeout to false. This is useful to find out if the peer + closed the connection. + + \warning This is a blocking call and should be avoided in event + driven applications. + + \sa bytesAvailable() +*/ + +/*! + \fn qint64 Q3SocketDevice::writeData( const char *data, qint64 len ) + + Writes \a len bytes to the socket from \a data and returns the + number of bytes written. Returns -1 if an error occurred. + + This is used for Q3SocketDevice::Stream sockets. +*/ + +/*! + \fn void Q3SocketDevice::fetchConnectionParameters() + + Fetches information about both ends of the connection: whatever is + available. +*/ + +/*! + \fn Q_UINT16 Q3SocketDevice::peerPort() const + + Returns the port number of the port this socket device is + connected to. This may be 0 for a while, but is set to something + sensible as soon as a sensible value is available. + + Note that for Datagram sockets, this is the source port of the + last packet received, and that it is in native byte order. +*/ + +/*! + \fn QHostAddress Q3SocketDevice::peerAddress() const + + Returns the address of the port this socket device is connected + to. This may be 0.0.0.0 for a while, but is set to something + sensible as soon as a sensible value is available. + + Note that for Datagram sockets, this is the source port of the + last packet received. +*/ + +QT_END_NAMESPACE + +#endif //QT_NO_NETWORK |