/* * 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. */ #include #include #ifdef USE_SOLARIS # include #endif #include #include #include #include #include #include #include #include #ifdef HAVE_POLL # include #else # ifdef HAVE_SYS_SELECT # include # endif #endif // Include syssocket before our local includes #include "syssocket.h" #include #include #include "kresolver.h" #include "tdesocketaddress.h" #include "tdesocketbase.h" #include "tdesocketdevice.h" #include "ksockssocketdevice.h" using namespace KNetwork; class KNetwork::TDESocketDevicePrivate { public: mutable TQSocketNotifier *input, *output, *exception; TDESocketAddress local, peer; int af; inline TDESocketDevicePrivate() { input = output = exception = 0L; af = 0; } }; TDESocketDevice::TDESocketDevice(const TDESocketBase* parent) : m_sockfd(-1), d(new TDESocketDevicePrivate) { setSocketDevice(this); if (parent) setSocketOptions(parent->socketOptions()); } TDESocketDevice::TDESocketDevice(int fd) : m_sockfd(fd), d(new TDESocketDevicePrivate) { setState(IO_Open); setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); setSocketDevice(this); d->af = localAddress().family(); } TDESocketDevice::TDESocketDevice(bool, const TDESocketBase* parent) : m_sockfd(-1), d(new TDESocketDevicePrivate) { // do not set parent if (parent) setSocketOptions(parent->socketOptions()); } TDESocketDevice::~TDESocketDevice() { close(); // deletes the notifiers unsetSocketDevice(); // prevent double deletion delete d; } bool TDESocketDevice::setSocketOptions(int opts) { // must call parent TQMutexLocker locker(mutex()); TDESocketBase::setSocketOptions(opts); if (m_sockfd == -1) return true; // flags are stored { int fdflags = fcntl(m_sockfd, F_GETFL, 0); if (fdflags == -1) { setError(IO_UnspecifiedError, UnknownError); return false; // error } if (opts & Blocking) fdflags &= ~O_NONBLOCK; else fdflags |= O_NONBLOCK; if (fcntl(m_sockfd, F_SETFL, fdflags) == -1) { setError(IO_UnspecifiedError, UnknownError); return false; // error } } { int on = opts & AddressReuseable ? 1 : 0; if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == -1) { setError(IO_UnspecifiedError, UnknownError); return false; // error } } #if defined(IPV6_V6ONLY) && defined(AF_INET6) if (d->af == AF_INET6) { // don't try this on non-IPv6 sockets, or we'll get an error int on = opts & IPv6Only ? 1 : 0; if (setsockopt(m_sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&on, sizeof(on)) == -1) { setError(IO_UnspecifiedError, UnknownError); return false; // error } } #endif { int on = opts & Broadcast ? 1 : 0; if (setsockopt(m_sockfd, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on)) == -1) { setError(IO_UnspecifiedError, UnknownError); return false; // error } } return true; // all went well } bool TDESocketDevice::open(TQ_OpenMode) { resetError(); return false; } void TDESocketDevice::close() { resetError(); if (m_sockfd != -1) { delete d->input; delete d->output; delete d->exception; d->input = d->output = d->exception = 0L; d->local.setFamily(AF_UNSPEC); d->peer.setFamily(AF_UNSPEC); ::close(m_sockfd); } setState(0); m_sockfd = -1; } bool TDESocketDevice::create(int family, int type, int protocol) { resetError(); if (m_sockfd != -1) { // it's already created! setError(IO_SocketCreateError, AlreadyCreated); return false; } // no socket yet; we have to create it m_sockfd = kde_socket(family, type, protocol); if (m_sockfd == -1) { setError(IO_SocketCreateError, NotSupported); return false; } d->af = family; setSocketOptions(socketOptions()); setState(IO_Open); return true; // successfully created } bool TDESocketDevice::create(const KResolverEntry& address) { return create(address.family(), address.socketType(), address.protocol()); } bool TDESocketDevice::bind(const KResolverEntry& address) { resetError(); if (m_sockfd == -1 && !create(address)) return false; // failed creating // we have a socket, so try and bind if (kde_bind(m_sockfd, address.address(), address.length()) == -1) { if (errno == EADDRINUSE) setError(IO_BindError, AddressInUse); else if (errno == EINVAL) setError(IO_BindError, AlreadyBound); else // assume the address is the cause setError(IO_BindError, NotSupported); return false; } return true; } bool TDESocketDevice::listen(int backlog) { if (m_sockfd != -1) { if (kde_listen(m_sockfd, backlog) == -1) { setError(IO_ListenError, NotSupported); return false; } resetError(); setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); return true; } // we don't have a socket // can't listen setError(IO_ListenError, NotCreated); return false; } bool TDESocketDevice::connect(const KResolverEntry& address) { resetError(); if (m_sockfd == -1 && !create(address)) return false; // failed creating! if (kde_connect(m_sockfd, address.address(), address.length()) == -1) { if (errno == EISCONN) return true; // we're already connected else if (errno == EALREADY || errno == EINPROGRESS) { setError(IO_ConnectError, InProgress); return true; } else if (errno == ECONNREFUSED) setError(IO_ConnectError, ConnectionRefused); else if (errno == ENETDOWN || errno == ENETUNREACH || errno == ENETRESET || errno == ECONNABORTED || errno == ECONNRESET || errno == EHOSTDOWN || errno == EHOSTUNREACH) setError(IO_ConnectError, NetFailure); else setError(IO_ConnectError, NotSupported); return false; } setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); return true; // all is well } TDESocketDevice* TDESocketDevice::accept() { if (m_sockfd == -1) { // can't accept without a socket setError(IO_AcceptError, NotCreated); return 0L; } struct sockaddr sa; socklen_t len = sizeof(sa); int newfd = kde_accept(m_sockfd, &sa, &len); if (newfd == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) setError(IO_AcceptError, WouldBlock); else setError(IO_AcceptError, UnknownError); return NULL; } return new TDESocketDevice(newfd); } bool TDESocketDevice::disconnect() { resetError(); if (m_sockfd == -1) return false; // can't create TDESocketAddress address; address.setFamily(AF_UNSPEC); if (kde_connect(m_sockfd, address.address(), address.length()) == -1) { if (errno == EALREADY || errno == EINPROGRESS) { setError(IO_ConnectError, InProgress); return false; } else if (errno == ECONNREFUSED) setError(IO_ConnectError, ConnectionRefused); else if (errno == ENETDOWN || errno == ENETUNREACH || errno == ENETRESET || errno == ECONNABORTED || errno == ECONNRESET || errno == EHOSTDOWN || errno == EHOSTUNREACH) setError(IO_ConnectError, NetFailure); else setError(IO_ConnectError, NotSupported); return false; } setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); setState(IO_Open); return true; // all is well } #ifdef USE_QT3 TQ_LONG TDESocketDevice::bytesAvailable() const #endif #ifdef USE_QT4 qint64 TDESocketDevice::bytesAvailable() const #endif { if (m_sockfd == -1) return -1; // there's nothing to read in a closed socket int nchars; if (ioctl(m_sockfd, FIONREAD, &nchars) == -1) return -1; // error! return nchars; } TQ_LONG TDESocketDevice::waitForMore(int msecs, bool *timeout) { if (m_sockfd == -1) return -1; // there won't ever be anything to read... bool input; if (!poll(&input, 0, 0, msecs, timeout)) return -1; // failed polling return bytesAvailable(); } static int do_read_common(int sockfd, char *data, TQ_ULONG maxlen, TDESocketAddress* from, ssize_t &retval, bool peek = false) { socklen_t len; if (from) { from->setLength(len = 128); // arbitrary length retval = ::recvfrom(sockfd, data, maxlen, peek ? MSG_PEEK : 0, from->address(), &len); } else retval = ::recvfrom(sockfd, data, maxlen, peek ? MSG_PEEK : 0, NULL, NULL); if (retval == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) return TDESocketDevice::WouldBlock; else return TDESocketDevice::UnknownError; } if (retval == 0) return TDESocketDevice::RemotelyDisconnected; if (from) from->setLength(len); return 0; } TQT_TQIO_LONG TDESocketDevice::tqreadBlock(char *data, TQT_TQIO_ULONG maxlen) { resetError(); if (m_sockfd == -1) return -1; if (maxlen == 0 || data == 0L) return 0; // can't read ssize_t retval; int err = do_read_common(m_sockfd, data, maxlen, 0L, retval); if (err) { setError(IO_ReadError, static_cast(err)); return -1; } return retval; } TQT_TQIO_LONG TDESocketDevice::tqreadBlock(char *data, TQT_TQIO_ULONG maxlen, TDESocketAddress &from) { resetError(); if (m_sockfd == -1) return -1; // nothing to do here if (data == 0L || maxlen == 0) return 0; // user doesn't want to read ssize_t retval; int err = do_read_common(m_sockfd, data, maxlen, &from, retval); if (err) { setError(IO_ReadError, static_cast(err)); return -1; } return retval; } TQ_LONG TDESocketDevice::peekBlock(char *data, TQ_ULONG maxlen) { resetError(); if (m_sockfd == -1) return -1; if (maxlen == 0 || data == 0L) return 0; // can't read ssize_t retval; int err = do_read_common(m_sockfd, data, maxlen, 0L, retval, true); if (err) { setError(IO_ReadError, static_cast(err)); return -1; } return retval; } TQ_LONG TDESocketDevice::peekBlock(char *data, TQ_ULONG maxlen, TDESocketAddress& from) { resetError(); if (m_sockfd == -1) return -1; // nothing to do here if (data == 0L || maxlen == 0) return 0; // user doesn't want to read ssize_t retval; int err = do_read_common(m_sockfd, data, maxlen, &from, retval, true); if (err) { setError(IO_ReadError, static_cast(err)); return -1; } return retval; } TQT_TQIO_LONG TDESocketDevice::tqwriteBlock(const char *data, TQT_TQIO_ULONG len) { return tqwriteBlock(data, len, TDESocketAddress()); } TQT_TQIO_LONG TDESocketDevice::tqwriteBlock(const char *data, TQT_TQIO_ULONG len, const TDESocketAddress& to) { resetError(); if (m_sockfd == -1) return -1; // can't write to unopen socket if (data == 0L || len == 0) return 0; // nothing to be written ssize_t retval = ::sendto(m_sockfd, data, len, 0, to.address(), to.length()); if (retval == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) setError(IO_WriteError, WouldBlock); else setError(IO_WriteError, UnknownError); return -1; // nothing written } else if (retval == 0) setError(IO_WriteError, RemotelyDisconnected); return retval; } TDESocketAddress TDESocketDevice::localAddress() const { if (m_sockfd == -1) return TDESocketAddress(); // not open, empty value if (d->local.family() != AF_UNSPEC) return d->local; socklen_t len; TDESocketAddress localAddress; localAddress.setLength(len = 32); // arbitrary value if (kde_getsockname(m_sockfd, localAddress.address(), &len) == -1) // error! return d->local = TDESocketAddress(); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN len = localAddress.address()->sa_len; #endif if (len <= localAddress.length()) { // it has fit already localAddress.setLength(len); return d->local = localAddress; } // no, the socket address is actually larger than we had anticipated // call again localAddress.setLength(len); if (kde_getsockname(m_sockfd, localAddress.address(), &len) == -1) // error! return d->local = TDESocketAddress(); return d->local = localAddress; } TDESocketAddress TDESocketDevice::peerAddress() const { if (m_sockfd == -1) return TDESocketAddress(); // not open, empty value if (d->peer.family() != AF_UNSPEC) return d->peer; socklen_t len; TDESocketAddress peerAddress; peerAddress.setLength(len = 32); // arbitrary value if (kde_getpeername(m_sockfd, peerAddress.address(), &len) == -1) // error! return d->peer = TDESocketAddress(); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN len = peerAddress.address()->sa_len; #endif if (len <= peerAddress.length()) { // it has fit already peerAddress.setLength(len); return d->peer = peerAddress; } // no, the socket address is actually larger than we had anticipated // call again peerAddress.setLength(len); if (kde_getpeername(m_sockfd, peerAddress.address(), &len) == -1) // error! return d->peer = TDESocketAddress(); return d->peer = peerAddress; } TDESocketAddress TDESocketDevice::externalAddress() const { // for normal sockets, the externally visible address is the same // as the local address return localAddress(); } TQSocketNotifier* TDESocketDevice::readNotifier() const { if (d->input) return d->input; TQMutexLocker locker(mutex()); if (d->input) return d->input; if (m_sockfd == -1) { // socket doesn't exist; can't create notifier return 0L; } return d->input = createNotifier(TQSocketNotifier::Read); } TQSocketNotifier* TDESocketDevice::writeNotifier() const { if (d->output) return d->output; TQMutexLocker locker(mutex()); if (d->output) return d->output; if (m_sockfd == -1) { // socket doesn't exist; can't create notifier return 0L; } return d->output = createNotifier(TQSocketNotifier::Write); } TQSocketNotifier* TDESocketDevice::exceptionNotifier() const { if (d->exception) return d->exception; TQMutexLocker locker(mutex()); if (d->exception) return d->exception; if (m_sockfd == -1) { // socket doesn't exist; can't create notifier return 0L; } return d->exception = createNotifier(TQSocketNotifier::Exception); } bool TDESocketDevice::poll(bool *input, bool *output, bool *exception, int timeout, bool* timedout) { if (m_sockfd == -1) { setError(IO_UnspecifiedError, NotCreated); return false; } resetError(); #ifdef HAVE_POLL struct pollfd fds; fds.fd = m_sockfd; fds.events = 0; if (input) { fds.events |= POLLIN; *input = false; } if (output) { fds.events |= POLLOUT; *output = false; } if (exception) { fds.events |= POLLPRI; *exception = false; } int retval = ::poll(&fds, 1, timeout); if (retval == -1) { setError(IO_UnspecifiedError, UnknownError); return false; } if (retval == 0) { // timeout if (timedout) *timedout = true; return true; } if (input && fds.revents & POLLIN) *input = true; if (output && fds.revents & POLLOUT) *output = true; if (exception && fds.revents & POLLPRI) *exception = true; if (timedout) *timedout = false; return true; #else /* * We don't have poll(2). We'll have to make do with select(2). */ fd_set readfds, writefds, exceptfds; fd_set *preadfds = 0L, *pwritefds = 0L, *pexceptfds = 0L; if (input) { preadfds = &readfds; FD_ZERO(preadfds); FD_SET(m_sockfd, preadfds); *input = false; } if (output) { pwritefds = &writefds; FD_ZERO(pwritefds); FD_SET(m_sockfd, pwritefds); *output = false; } if (exception) { pexceptfds = &exceptfds; FD_ZERO(pexceptfds); FD_SET(m_sockfd, pexceptfds); *exception = false; } int retval; if (timeout < 0) retval = select(m_sockfd + 1, preadfds, pwritefds, pexceptfds, 0L); else { // convert the milliseconds to timeval struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = timeout % 1000 * 1000; retval = select(m_sockfd + 1, preadfds, pwritefds, pexceptfds, &tv); } if (retval == -1) { setError(IO_UnspecifiedError, UnknownError); return false; } if (retval == 0) { // timeout if (timedout) *timedout = true; return true; } if (input && FD_ISSET(m_sockfd, preadfds)) *input = true; if (output && FD_ISSET(m_sockfd, pwritefds)) *output = true; if (exception && FD_ISSET(m_sockfd, pexceptfds)) *exception = true; return true; #endif } bool TDESocketDevice::poll(int timeout, bool *timedout) { bool input, output, exception; return poll(&input, &output, &exception, timeout, timedout); } TQSocketNotifier* TDESocketDevice::createNotifier(TQSocketNotifier::Type type) const { if (m_sockfd == -1) return 0L; return new TQSocketNotifier(m_sockfd, type); } namespace { // simple class to avoid pointer stuff template class ptr { typedef T type; type* obj; public: ptr() : obj(0) { } ptr(const ptr& other) : obj(other.obj) { } ptr(type* _obj) : obj(_obj) { } ~ptr() { } ptr& operator=(const ptr& other) { obj = other.obj; return *this; } ptr& operator=(T* _obj) { obj = _obj; return *this; } type* operator->() const { return obj; } operator T*() const { return obj; } bool isNull() const { return obj == 0; } }; } static TDESocketDeviceFactoryBase* defaultImplFactory; static TQMutex defaultImplFactoryMutex; typedef TQMap factoryMap; static factoryMap factories; TDESocketDevice* TDESocketDevice::createDefault(TDESocketBase* parent) { TDESocketDevice* device = dynamic_cast(parent); if (device != 0L) return device; KSocksSocketDevice::initSocks(); if (defaultImplFactory) return defaultImplFactory->create(parent); // the really default return new TDESocketDevice(parent); } TDESocketDevice* TDESocketDevice::createDefault(TDESocketBase* parent, int capabilities) { TDESocketDevice* device = dynamic_cast(parent); if (device != 0L) return device; TQMutexLocker locker(&defaultImplFactoryMutex); factoryMap::ConstIterator it = factories.constBegin(); for ( ; it != factories.constEnd(); ++it) if ((it.key() & capabilities) == capabilities) // found a match return it.data()->create(parent); return 0L; // no default } TDESocketDeviceFactoryBase* TDESocketDevice::setDefaultImpl(TDESocketDeviceFactoryBase* factory) { TQMutexLocker locker(&defaultImplFactoryMutex); TDESocketDeviceFactoryBase* old = defaultImplFactory; defaultImplFactory = factory; return old; } void TDESocketDevice::addNewImpl(TDESocketDeviceFactoryBase* factory, int capabilities) { TQMutexLocker locker(&defaultImplFactoryMutex); if (factories.contains(capabilities)) delete factories[capabilities]; factories.insert(capabilities, factory); }