/* -*- C++ -*- * Copyright (C) 2003,2005 Thiago Macieira * * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Even before our #ifdef, clean up the namespace */ #ifdef socket #undef socket #endif #ifdef bind #undef bind #endif #ifdef listen #undef listen #endif #ifdef connect #undef connect #endif #ifdef accept #undef accept #endif #ifdef getpeername #undef getpeername #endif #ifdef getsockname #undef getsockname #endif #ifndef TDESOCKETBASE_H #define TDESOCKETBASE_H #include #include #include "tdesocketaddress.h" #include /* * This is extending QIODevice's error codes * * According to tqiodevice.h, the last error is IO_UnspecifiedError * These errors will never occur in functions declared in QIODevice * (except open, but you shouldn't call open) */ #define IO_ListenError (IO_UnspecifiedError+1) #define IO_AcceptError (IO_UnspecifiedError+2) #define IO_LookupError (IO_UnspecifiedError+3) #define IO_SocketCreateError (IO_UnspecifiedError+4) #define IO_BindError (IO_UnspecifiedError+5) class TQMutex; namespace KNetwork { class KResolverEntry; class TDESocketDevice; class TDESocketBasePrivate; /** @class TDESocketBase tdesocketbase.h tdesocketbase.h * @brief Basic socket functionality. * * This class provides the basic socket functionlity for descended classes. * Socket classes are thread-safe and provide a recursive mutex should it be * needed. * * @note This class is abstract. * * @author Thiago Macieira */ class TDECORE_EXPORT TDESocketBase { public: /** * Possible socket options. * * These are the options that may be set on a socket: * - Blocking: whether the socket shall operate in blocking * or non-blocking mode. This flag defaults to on. * See @ref setBlocking. * - AddressReusable: whether the address used by this socket will * be available for reuse by other sockets. This flag defaults to off. * See @ref setAddressReuseable. * - IPv6Only: whether an IPv6 socket will accept IPv4 connections * through a mapped address. This flag defaults to off. * See @ref setIPv6Only. * - KeepAlive: whether TCP should send keepalive probes when a connection * has gone idle for far too long. * - Broadcast: whether this socket is allowed to send broadcast packets * and will receive packets sent to broadcast. */ enum SocketOptions { Blocking = 0x01, AddressReuseable = 0x02, IPv6Only = 0x04, Keepalive = 0x08, Broadcast = 0x10 }; /** * Possible socket error codes. * * This is a list of possible error conditions that socket classes may * be expected to find. * * - NoError: no error has been detected * - LookupFailure: if a name lookup has failed * - AddressInUse: address is already in use * - AlreadyBound: cannot bind again * - AlreadyCreated: cannot recreate the socket * - NotBound: operation required socket to be bound and it isn't * - NotCreated: operation required socket to exist and it doesn't * - WouldBlock: requested I/O operation would block * - ConnectionRefused: connection actively refused * - ConnectionTimedOut: connection timed out * - InProgress: operation (connection) is already in progress * - NetFailure: a network failure occurred (no route, host down, host unreachable or similar) * - NotSupported: requested operation is not supported * - Timeout: a timed operation timed out * - UnknownError: an unknown/unexpected error has happened * - RemotelyDisconnected: when a connection is disconnected by the other end (since 3.4) * * @sa error, errorString */ enum SocketError { NoError = 0, LookupFailure, AddressInUse, AlreadyCreated, AlreadyBound, AlreadyConnected, NotConnected, NotBound, NotCreated, WouldBlock, ConnectionRefused, ConnectionTimedOut, InProgress, NetFailure, NotSupported, Timeout, UnknownError, RemotelyDisconnected }; public: /** * Default constructor. */ TDESocketBase(); /** * Destructor. */ virtual ~TDESocketBase(); /* * The following functions are shared by all descended classes and will have * to be reimplemented. */ protected: /** * Set the given socket options. * * The default implementation does nothing but store the mask internally. * Descended classes must override this function to achieve functionality and * must also call this implementation. * * @param opts a mask of @ref SocketOptions or-ed bits of options to set * or unset * @returns true on success * @note this function sets the options corresponding to the bits enabled in @p opts * but will also unset the optiosn corresponding to the bits not set. */ virtual bool setSocketOptions(int opts); /** * Retrieves the socket options that have been set. * * The default implementation just retrieves the mask from an internal variable. * Descended classes may choose to override this function to read the values * from the operating system. * * @returns the mask of the options set */ virtual int socketOptions() const; public: /** * Sets this socket's blocking mode. * * In blocking operation, all I/O functions are susceptible to blocking -- * i.e., will not return unless the I/O can be satisfied. In non-blocking * operation, if the I/O would block, the function will return an error * and set the corresponding error code. * * The default implementation toggles the Blocking flag with the current * socket options and calls @ref setSocketOptions. * * @param enable whether to set this socket to blocking mode * @returns whether setting this value was successful; it is NOT the * final blocking mode. */ virtual bool setBlocking(bool enable); /** * Retrieves this socket's blocking mode. * * @returns true if this socket is/will be operated in blocking mode, * false if non-blocking. */ bool blocking() const; /** * Sets this socket's address reuseable flag. * * When the address reuseable flag is active, the address used by * this socket is left reuseable for other sockets to bind. If * the flag is not active, no other sockets may reuse the same * address. * * The default implementation toggles the AddressReuseable flag with the current * socket options and calls @ref setSocketOptions. * * @param enable whether to set the flag on or off * @returns true if setting this flag was successful */ virtual bool setAddressReuseable(bool enable); /** * Retrieves this socket's address reuseability flag. * * @returns true if this socket's address can be reused, * false if it can't. */ bool addressReuseable() const; /** * Sets this socket's IPv6 Only flag. * * When this flag is on, an IPv6 socket will only accept, connect, send to or * receive from IPv6 addresses. When it is off, it will also talk to * IPv4 addresses through v4-mapped addresses. * * This option has no effect on non-IPv6 sockets. * * The default implementation toggles the IPv6Only flag with the current * socket options and calls @ref setSocketOptions. * * @param enable whether to set the flag on or off * @returns true if setting this flag was successful */ virtual bool setIPv6Only(bool enable); /** * Retrieves this socket's IPv6 Only flag. * * @returns true if this socket will ignore IPv4-compatible and IPv4-mapped * addresses, false if it will accept them. */ bool isIPv6Only() const; /** * Sets this socket Broadcast flag. * * Datagram-oriented sockets cannot normally send packets to broadcast * addresses, nor will they receive packets that were sent to a broadcast * address. To do so, you need to enable the Broadcast flag. * * This option has no effect on stream-oriented sockets. * * @returns true if setting this flag was successful. */ virtual bool setBroadcast(bool enable); /** * Retrieves this socket's Broadcast flag. * * @returns true if this socket can send and receive broadcast packets, * false if it can't. */ bool broadcast() const; /** * Retrieves the socket implementation used on this socket. * * This function creates the device if none has been set * using the default factory. */ TDESocketDevice* socketDevice() const; /** * Sets the socket implementation to be used on this socket. * * Note: it is an error to set this if the socket device has * already been set once. * * This function is provided virtual so that derived classes can catch * the setting of a device and properly set their own states and internal * variables. The parent class must be called. * * This function is called by @ref socketDevice above when the socket is * first created. */ virtual void setSocketDevice(TDESocketDevice* device); /** * Sets the internally requested capabilities for a socket device. * * Most socket classes can use any back-end implementation. However, a few * may require specific capabilities not provided in the default * implementation. By using this function, derived classes can request * that a backend with those capabilities be created when necessary. * * For the possible flags, see @ref TDESocketDevice::Capabilities. However, note * that only the Can* flags make sense in this context. * * @note Since socketDevice must always return a valid backend object, it * is is possible that the created device does not conform to all * requirements requested. Implementations sensitive to this fact * should test the object returned by @ref socketDevice (through * @ref TDESocketDevice::capabilities, for instance) the availability. * * @param add mask of @ref TDESocketDevice::Capabilities to add * @param remove mask of bits to remove from the requirements * @return the current mask of requested capabilities */ int setRequestedCapabilities(int add, int remove = 0); protected: /** * Returns true if the socket device has been initialised in this * object, either by calling @ref socketDevice() or @ref setSocketDevice */ bool hasDevice() const; /** * Sets the socket's error code. * * @param error the error code */ void setError(SocketError error); public: /** * Retrieves the socket error code. * @sa errorString */ SocketError error() const; /** * Returns the error string corresponding to this error condition. */ inline TQString errorString() const { return errorString(error()); } /** * Returns the internal mutex for this class. * * Note on multithreaded use of sockets: * the socket classes are thread-safe by design, but you should be aware of * problems regarding socket creation, connection and destruction in * multi-threaded programs. The classes are guaranteed to work while * the socket exists, but it's not wise to call connect in multiple * threads. * * Also, this mutex must be unlocked before the object is destroyed, which * means you cannot use it to guard against other threads accessing the object * while destroying it. You must ensure there are no further references to this * object when deleting it. */ TQMutex* mutex() const; public: /** * Returns the string describing the given error code, i18n'ed. * * @param code the error code */ static TQString errorString(SocketError code); /** * Returns true if the given error code is a fatal one, false * otherwise. The parameter here is of type int so that * casting isn't necessary when using the parameter to signal * QClientSocketBase::gotError. * * @param code the code to test */ static bool isFatalError(int code); private: /// @internal /// called by TDESocketDevice void unsetSocketDevice(); TDESocketBase(const TDESocketBase&); TDESocketBase& operator =(const TDESocketBase&); TDESocketBasePrivate *d; friend class TDESocketDevice; }; /** * @class KActiveSocketBase tdesocketbase.h tdesocketbase.h * @brief Abstract class for active sockets * * This class provides the standard interfaces for active sockets, i.e., * sockets that are used to connect to external addresses. * * @author Thiago Macieira */ class TDECORE_EXPORT KActiveSocketBase: public TQIODevice, virtual public TDESocketBase { public: /** * Constructor. */ KActiveSocketBase(); /** * Destructor. */ virtual ~KActiveSocketBase(); /** * Binds this socket to the given address. * * The socket will be constructed with the address family, * socket type and protocol as those given in the * @p address object. * * @param address the address to bind to * @returns true if the binding was successful, false otherwise */ virtual bool bind(const KResolverEntry& address) = 0; /** * Connect to a remote host. * * This will make this socket try to connect to the remote host. * If the socket is not yet created, it will be created using the * address family, socket type and protocol specified in the * @p address object. * * If this function returns with error InProgress, calling it * again with the same address after a time will cause it to test * if the connection has succeeded in the mean time. * * @param address the address to connect to * @returns true if the connection was successful or has been successfully * queued; false if an error occurred. */ virtual bool connect(const KResolverEntry& address) = 0; /** * Disconnects this socket from a connection, if possible. * * If this socket was connected to an endpoint, the connection * is severed, but the socket is not closed. If the socket wasn't * connected, this function does nothing. * * If the socket hadn't yet been created, this function does nothing * either. * * Not all socket types can disconnect. Most notably, only * connectionless datagram protocols such as UDP support this operation. * * @return true if the socket is now disconnected or false on error. */ virtual bool disconnect() = 0; /** * This call is not supported on sockets. Reimplemented from TQIODevice. * This will always return 0. */ #ifdef USE_QT4 virtual qint64 size() const #else // USE_QT4 virtual Offset size() const #endif // USE_QT4 { return 0; } /** * This call is not supported on sockets. Reimplemented from TQIODevice. * This will always return 0. */ virtual Offset at() const { return 0; } /** * This call is not supported on sockets. Reimplemented from TQIODevice. * This will always return false. */ virtual bool at(Offset) { return false; } /** * This call is not supported on sockets. Reimplemented from TQIODevice. * This will always return true. */ virtual bool atEnd() const { return true; } /** * Returns the number of bytes available for reading without * blocking. */ #ifdef USE_QT3 virtual TQ_LONG bytesAvailable() const = 0; #endif #ifdef USE_QT4 virtual qint64 bytesAvailable() const = 0; #endif /** * Waits up to @p msecs for more data to be available on this socket. * * If msecs is -1, this call will block indefinetely until more data * is indeed available; if it's 0, this function returns immediately. * * If @p timeout is not NULL, this function will set it to indicate * if a timeout occurred. * * @returns the number of bytes available */ virtual TQ_LONG waitForMore(int msecs, bool *timeout = 0L) = 0; /** * Reads data from the socket. * * Reimplemented from TQIODevice. See TQIODevice::readBlock for * more information. */ virtual TQT_TQIO_LONG tqreadBlock(char *data, TQT_TQIO_ULONG len) = 0; /** @overload * Receives data and the source address. * * This call will read data in the socket and will also * place the sender's address in @p from object. * * @param data where to write the read data to * @param maxlen the maximum number of bytes to read * @param from the address of the sender will be stored here * @returns the actual number of bytes read */ virtual TQT_TQIO_LONG tqreadBlock(char *data, TQT_TQIO_ULONG maxlen, TDESocketAddress& from) = 0; /** * Peeks the data in the socket. * * This call will allow you to peek the data to be received without actually * receiving it -- that is, it will be available for further peekings and * for the next read call. * * @param data where to write the peeked data to * @param maxlen the maximum number of bytes to peek * @returns the actual number of bytes copied into @p data */ virtual TQ_LONG peekBlock(char *data, TQ_ULONG maxlen) = 0; /** @overload * Peeks the data in the socket and the source address. * * This call will allow you to peek the data to be received without actually * receiving it -- that is, it will be available for further peekings and * for the next read call. * * @param data where to write the peeked data to * @param maxlen the maximum number of bytes to peek * @param from the address of the sender will be stored here * @returns the actual number of bytes copied into @p data */ virtual TQ_LONG peekBlock(char *data, TQ_ULONG maxlen, TDESocketAddress& from) = 0; /** * Writes the given data to the socket. * * Reimplemented from TQIODevice. See TQIODevice::writeBlock for * more information. */ virtual TQT_TQIO_LONG tqwriteBlock(const char *data, TQT_TQIO_ULONG len) = 0; /** @overload * Writes the given data to the destination address. * * Note that not all socket connections allow sending data to different * addresses than the one the socket is connected to. * * @param data the data to write * @param len the length of the data * @param to the address to send to * @returns the number of bytes actually sent */ virtual TQT_TQIO_LONG tqwriteBlock(const char *data, TQT_TQIO_ULONG len, const TDESocketAddress& to) = 0; /** * Reads one character from the socket. * Reimplementation from TQIODevice. See TQIODevice::getch for more information. */ virtual int getch(); /** * Writes one character to the socket. * Reimplementation from TQIODevice. See TQIODevice::putch for more information. */ virtual int putch(int ch); /** * This call is not supported on sockets. Reimplemented from TQIODevice. * This will always return -1; */ virtual int ungetch(int) { return -1; } /** * Returns this socket's local address. */ virtual TDESocketAddress localAddress() const = 0; /** * Return this socket's peer address, if we are connected. * If the address cannot be retrieved, the returned object will contain * an invalid address. */ virtual TDESocketAddress peerAddress() const = 0; // FIXME KDE 4.0: // enable this function #if 0 /** * Returns this socket's externally-visible address, if known. */ virtual TDESocketAddress externalAddress() const = 0; #endif protected: /** * Sets the socket's error code and the I/O Device's status. * * @param status the I/O Device status * @param error the error code */ void setError(int status, SocketError error); /** * Resets the socket error code and the I/O Device's status. */ void resetError(); }; /** * @class KPassiveSocketBase tdesocketbase.h tdesocketbase.h * @brief Abstract base class for passive sockets. * * This socket provides the initial functionality for passive sockets, * i.e., sockets that accept incoming connections. * * @author Thiago Macieira */ class TDECORE_EXPORT KPassiveSocketBase: virtual public TDESocketBase { public: /** * Constructor */ KPassiveSocketBase(); /** * Destructor */ virtual ~KPassiveSocketBase(); /** * Binds this socket to the given address. * * The socket will be constructed with the address family, * socket type and protocol as those given in the * @p address object. * * @param address the address to bind to * @returns true if the binding was successful, false otherwise */ virtual bool bind(const KResolverEntry& address) = 0; /** * Puts this socket into listening mode. * * Placing a socket in listening mode means that it will * be allowed to receive incoming connections from * remote hosts. * * Note that some socket types or protocols cannot be * put in listening mode. * * @param backlog the number of accepted connections to * hold before starting to refuse * @returns true if the socket is now in listening mode */ virtual bool listen(int backlog) = 0; /** * Closes this socket. All resources used are freed. Note that closing * a passive socket does not close the connections accepted with it. */ virtual void close() = 0; /** * Accepts a new incoming connection. * * If this socket was in listening mode, you can call this * function to accept an incoming connection. * * If this function cannot accept a new connection (either * because it is not listening for one or because the operation * would block), it will return NULL. * * Also note that descended classes will override this function * to return specialised socket classes. */ virtual KActiveSocketBase* accept() = 0; /** * Returns this socket's local address. */ virtual TDESocketAddress localAddress() const = 0; /** * Returns this socket's externally-visible address if known. */ virtual TDESocketAddress externalAddress() const = 0; private: KPassiveSocketBase(const KPassiveSocketBase&); KPassiveSocketBase& operator = (const KPassiveSocketBase&); }; } // namespace KNetwork #endif