src/qt3support/network/q3socketdevice.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/qt3support/network/q3socketdevice.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,757 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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