// // Socket.h // // Library: Net // Package: Sockets // Module: Socket // // Definition of the Socket class. // // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // #ifndef Net_Socket_INCLUDED #define Net_Socket_INCLUDED #include "Poco/Net/Net.h" #include "Poco/Net/SocketImpl.h" #include #ifdef POCO_NEW_STATE_ON_MOVE #define POCO_CHECK_NEW_STATE_ON_MOVE poco_assert_dbg(POCO_NEW_STATE_ON_MOVE && _pImpl); #else #define POCO_CHECK_NEW_STATE_ON_MOVE #endif namespace Poco { namespace Net { class Net_API Socket /// Socket is the common base class for /// StreamSocket, ServerSocket, DatagramSocket and other /// socket classes. /// /// It provides operations common to all socket types. { public: using BufVec = SocketBufVec; using Type = SocketImpl::Type; using SocketList = std::vector; enum SelectMode /// The mode argument to poll() and select(). { SELECT_READ = 1, SELECT_WRITE = 2, SELECT_ERROR = 4 }; Socket(); /// Creates an uninitialized socket. Socket(const Socket& socket); /// Copy constructor. /// /// Attaches the SocketImpl from the other socket and /// increments the reference count of the SocketImpl. Socket& operator = (const Socket& socket); /// Assignment operator. /// /// Releases the socket's SocketImpl and /// attaches the SocketImpl from the other socket and /// increments the reference count of the SocketImpl. #if POCO_NEW_STATE_ON_MOVE Socket(Socket&& socket); /// Move constructor. /// /// Attaches the SocketImpl from the other socket and /// zeroes the other socket's SocketImpl. Socket& operator = (Socket&& socket); /// Assignment move operator. /// /// Releases the socket's SocketImpl, /// attaches the SocketImpl from the other socket, /// and zeroes the other socket's SocketImpl. #endif // POCO_NEW_STATE_ON_MOVE static Socket fromFileDescriptor(poco_socket_t fd); // Creates a socket from an existing file descriptor. // Ownership is taken by poco virtual ~Socket(); /// Destroys the Socket and releases the /// SocketImpl. bool operator == (const Socket& socket) const; /// Returns true if both sockets share the same /// SocketImpl, false otherwise. bool operator != (const Socket& socket) const; /// Returns false if both sockets share the same /// SocketImpl, true otherwise. bool operator < (const Socket& socket) const; /// Compares the SocketImpl pointers. bool operator <= (const Socket& socket) const; /// Compares the SocketImpl pointers. bool operator > (const Socket& socket) const; /// Compares the SocketImpl pointers. bool operator >= (const Socket& socket) const; /// Compares the SocketImpl pointers. bool isNull() const; /// Returns true if pointer to implementation is null. Type type() const; /// Returns the socket type. bool isStream() const; /// Returns true if socket is a stream socket, /// false otherwise. bool isDatagram() const; /// Returns true if socket is a datagram socket, /// false otherwise. bool isRaw() const; /// Returns true if socket is a raw socket, /// false otherwise. void close(); /// Closes the socket. POCO_DEPRECATED("Use PollSet instead") static int select(SocketList& readList, SocketList& writeList, SocketList& exceptList, const Poco::Timespan& timeout); /// Determines the status of one or more sockets, /// using a call to select(). /// /// ReadList contains the list of sockets which should be /// checked for readability. /// /// WriteList contains the list of sockets which should be /// checked for writeability. /// /// ExceptList contains a list of sockets which should be /// checked for a pending error. /// /// Returns the number of sockets ready. /// /// After return, /// * readList contains those sockets ready for reading, /// * writeList contains those sockets ready for writing, /// * exceptList contains those sockets with a pending error. /// /// If the total number of sockets passed in readList, writeList and /// exceptList is zero, select() will return immediately and the /// return value will be 0. /// /// If one of the sockets passed to select() is closed while /// select() runs, select will return immediately. However, /// the closed socket will not be included in any list. /// In this case, the return value may be greater than the sum /// of all sockets in all list. /// /// This function is deprecated and may be removed in the future releases, /// please use PollSet class instead. bool poll(const Poco::Timespan& timeout, int mode) const; /// Determines the status of the socket, using a /// call to poll() or select(). /// /// The mode argument is constructed by combining the values /// of the SelectMode enumeration. /// /// Returns true if the next operation corresponding to /// mode will not block, false otherwise. int available() const; /// Returns the number of bytes available that can be read /// without causing the socket to block. int getError() const; /// Returns the socket error. void setSendBufferSize(int size); /// Sets the size of the send buffer. int getSendBufferSize() const; /// Returns the size of the send buffer. /// /// The returned value may be different than the /// value previously set with setSendBufferSize(), /// as the system is free to adjust the value. void setReceiveBufferSize(int size); /// Sets the size of the receive buffer. int getReceiveBufferSize() const; /// Returns the size of the receive buffer. /// /// The returned value may be different than the /// value previously set with setReceiveBufferSize(), /// as the system is free to adjust the value. void setSendTimeout(const Poco::Timespan& timeout); /// Sets the send timeout for the socket. Poco::Timespan getSendTimeout() const; /// Returns the send timeout for the socket. /// /// The returned timeout may be different than the /// timeout previously set with setSendTimeout(), /// as the system is free to adjust the value. void setReceiveTimeout(const Poco::Timespan& timeout); /// Sets the receive timeout for the socket. /// /// On systems that do not support SO_RCVTIMEO, a /// workaround using poll() is provided. Poco::Timespan getReceiveTimeout() const; /// Returns the receive timeout for the socket. /// /// The returned timeout may be different than the /// timeout previously set with getReceiveTimeout(), /// as the system is free to adjust the value. void setOption(int level, int option, int value); /// Sets the socket option specified by level and option /// to the given integer value. void setOption(int level, int option, unsigned value); /// Sets the socket option specified by level and option /// to the given integer value. void setOption(int level, int option, unsigned char value); /// Sets the socket option specified by level and option /// to the given integer value. void setOption(int level, int option, const Poco::Timespan& value); /// Sets the socket option specified by level and option /// to the given time value. void setOption(int level, int option, const IPAddress& value); /// Sets the socket option specified by level and option /// to the given time value. void getOption(int level, int option, int& value) const; /// Returns the value of the socket option /// specified by level and option. void getOption(int level, int option, unsigned& value) const; /// Returns the value of the socket option /// specified by level and option. void getOption(int level, int option, unsigned char& value) const; /// Returns the value of the socket option /// specified by level and option. void getOption(int level, int option, Poco::Timespan& value) const; /// Returns the value of the socket option /// specified by level and option. void getOption(int level, int option, IPAddress& value) const; /// Returns the value of the socket option /// specified by level and option. void setLinger(bool on, int seconds); /// Sets the value of the SO_LINGER socket option. void getLinger(bool& on, int& seconds) const; /// Returns the value of the SO_LINGER socket option. void setNoDelay(bool flag); /// Sets the value of the TCP_NODELAY socket option. bool getNoDelay() const; /// Returns the value of the TCP_NODELAY socket option. void setKeepAlive(bool flag); /// Sets the value of the SO_KEEPALIVE socket option. bool getKeepAlive() const; /// Returns the value of the SO_KEEPALIVE socket option. void setReuseAddress(bool flag); /// Sets the value of the SO_REUSEADDR socket option. bool getReuseAddress() const; /// Returns the value of the SO_REUSEADDR socket option. void setReusePort(bool flag); /// Sets the value of the SO_REUSEPORT socket option. /// Does nothing if the socket implementation does not /// support SO_REUSEPORT. bool getReusePort() const; /// Returns the value of the SO_REUSEPORT socket option. /// /// Returns false if the socket implementation does not /// support SO_REUSEPORT. void setOOBInline(bool flag); /// Sets the value of the SO_OOBINLINE socket option. bool getOOBInline() const; /// Returns the value of the SO_OOBINLINE socket option. void setBlocking(bool flag); /// Sets the socket in blocking mode if flag is true, /// disables blocking mode if flag is false. bool getBlocking() const; /// Returns the blocking mode of the socket. /// This method will only work if the blocking modes of /// the socket are changed via the setBlocking method! SocketAddress address() const; /// Returns the IP address and port number of the socket. SocketAddress peerAddress() const; /// Returns the IP address and port number of the peer socket. SocketImpl* impl() const; /// Returns the SocketImpl for this socket. bool secure() const; /// Returns true iff the socket's connection is secure /// (using SSL or TLS). static bool supportsIPv4(); /// Returns true if the system supports IPv4. static bool supportsIPv6(); /// Returns true if the system supports IPv6. void init(int af); /// Creates the underlying system socket for the given /// address family. /// /// Normally, this method should not be called directly, as /// socket creation will be handled automatically. There are /// a few situations where calling this method after creation /// of the Socket object makes sense. One example is setting /// a socket option before calling bind() on a ServerSocket. static SocketBuf makeBuffer(void* buffer, std::size_t length); /// Creates and returns buffer. Suitable for creating /// the appropriate buffer for the platform. static SocketBufVec makeBufVec(std::size_t size, std::size_t bufLen); /// Creates and returns a vector of requested size, with /// allocated buffers and lengths set accordingly. /// This utility function works well when all buffers are /// of same size. static void destroyBufVec(SocketBufVec& buf); /// Releases the memory pointed to by vector members /// and shrinks the vector to size 0. /// The vector must be created by makeBufVec(size_t, size_t). static SocketBufVec makeBufVec(const std::vector& vec); /// Creates and returns a vector of requested size, with /// buffers pointing to the supplied data (so, `vec` must /// remain available at the time of use) and lengths set /// accordingly. /// Notes: /// - data length is determined using `strlen`, so this /// function is not meant to be used with binary data. /// /// - if the returned buffer is used for read operations /// (ie. operations that write to the bufer), pointing /// to string literals will result in undefined behavior, /// in best case an I/O error and subsequent exception static SocketBufVec makeBufVec(const std::vector& vec); /// Creates and returns a vector of requested size, with /// buffers pointing to the supplied data (so, `vec` must /// remain available at the time of use) and lengths set /// accordingly. /// Note:: this function is not suitable for creation /// of buffers used for writing (ie. reading from socket /// into buffers). static int lastError(); /// Returns the last error code. static std::string lastErrorDesc(); /// Returns the last error description. static void error(); /// Throws an appropriate exception for the last error. protected: Socket(SocketImpl* pImpl); /// Creates the Socket and attaches the given SocketImpl. /// The socket takes ownership of the SocketImpl. poco_socket_t sockfd() const; /// Returns the socket descriptor for this socket. private: #if defined(POCO_HAVE_FD_POLL) class FDCompare /// Utility functor used to compare socket file descriptors. /// Used in poll() member function. { public: FDCompare(int fd): _fd(fd) { } FDCompare() = delete; inline bool operator()(const Socket& socket) const { return socket.sockfd() == _fd; } private: int _fd; }; #endif SocketImpl* _pImpl; }; // // inlines // inline bool Socket::operator == (const Socket& socket) const { return _pImpl == socket._pImpl; } inline bool Socket::operator != (const Socket& socket) const { return _pImpl != socket._pImpl; } inline bool Socket::operator < (const Socket& socket) const { return _pImpl < socket._pImpl; } inline bool Socket::operator <= (const Socket& socket) const { return _pImpl <= socket._pImpl; } inline bool Socket::operator > (const Socket& socket) const { return _pImpl > socket._pImpl; } inline bool Socket::operator >= (const Socket& socket) const { return _pImpl >= socket._pImpl; } inline Socket::Type Socket::type() const { return _pImpl->type(); } inline bool Socket::isStream() const { return type() == Type::SOCKET_TYPE_STREAM; } inline bool Socket::isDatagram() const { return type() == Type::SOCKET_TYPE_DATAGRAM; } inline bool Socket::isRaw() const { return type() == Type::SOCKET_TYPE_RAW; } inline bool Socket::isNull() const { return _pImpl == nullptr; } inline void Socket::close() { if (_pImpl) _pImpl->close(); } inline bool Socket::poll(const Poco::Timespan& timeout, int mode) const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->poll(timeout, mode); } inline int Socket::available() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->available(); } inline int Socket::getError() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getError(); } inline void Socket::setSendBufferSize(int size) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setSendBufferSize(size); } inline int Socket::getSendBufferSize() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getSendBufferSize(); } inline void Socket::setReceiveBufferSize(int size) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setReceiveBufferSize(size); } inline int Socket::getReceiveBufferSize() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getReceiveBufferSize(); } inline void Socket::setSendTimeout(const Poco::Timespan& timeout) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setSendTimeout(timeout); } inline Poco::Timespan Socket::getSendTimeout() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getSendTimeout(); } inline void Socket::setReceiveTimeout(const Poco::Timespan& timeout) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setReceiveTimeout(timeout); } inline Poco::Timespan Socket::getReceiveTimeout() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getReceiveTimeout(); } inline void Socket::setOption(int level, int option, int value) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setOption(level, option, value); } inline void Socket::setOption(int level, int option, unsigned value) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setOption(level, option, value); } inline void Socket::setOption(int level, int option, unsigned char value) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setOption(level, option, value); } inline void Socket::setOption(int level, int option, const Poco::Timespan& value) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setOption(level, option, value); } inline void Socket::setOption(int level, int option, const IPAddress& value) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setOption(level, option, value); } inline void Socket::getOption(int level, int option, int& value) const { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->getOption(level, option, value); } inline void Socket::getOption(int level, int option, unsigned& value) const { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->getOption(level, option, value); } inline void Socket::getOption(int level, int option, unsigned char& value) const { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->getOption(level, option, value); } inline void Socket::getOption(int level, int option, Poco::Timespan& value) const { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->getOption(level, option, value); } inline void Socket::getOption(int level, int option, IPAddress& value) const { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->getOption(level, option, value); } inline void Socket::setLinger(bool on, int seconds) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setLinger(on, seconds); } inline void Socket::getLinger(bool& on, int& seconds) const { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->getLinger(on, seconds); } inline void Socket::setNoDelay(bool flag) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setNoDelay(flag); } inline bool Socket::getNoDelay() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getNoDelay(); } inline void Socket::setKeepAlive(bool flag) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setKeepAlive(flag); } inline bool Socket::getKeepAlive() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getKeepAlive(); } inline void Socket::setReuseAddress(bool flag) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setReuseAddress(flag); } inline bool Socket::getReuseAddress() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getReuseAddress(); } inline void Socket::setReusePort(bool flag) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setReusePort(flag); } inline bool Socket::getReusePort() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getReusePort(); } inline void Socket::setOOBInline(bool flag) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setOOBInline(flag); } inline bool Socket::getOOBInline() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getOOBInline(); } inline void Socket::setBlocking(bool flag) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->setBlocking(flag); } inline bool Socket::getBlocking() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->getBlocking(); } inline SocketImpl* Socket::impl() const { return _pImpl; } inline poco_socket_t Socket::sockfd() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->sockfd(); } inline SocketAddress Socket::address() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->address(); } inline SocketAddress Socket::peerAddress() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->peerAddress(); } inline bool Socket::secure() const { POCO_CHECK_NEW_STATE_ON_MOVE; return _pImpl->secure(); } inline bool Socket::supportsIPv4() { return true; } inline bool Socket::supportsIPv6() { #if defined(POCO_HAVE_IPv6) return true; #else return false; #endif } inline void Socket::init(int af) { POCO_CHECK_NEW_STATE_ON_MOVE; _pImpl->init(af); } } } // namespace Poco::Net #endif // Net_Socket_INCLUDED