From 255918c59ce22a1523436e8a9b703c54e753106f Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Mon, 30 Jan 2012 20:18:15 -0600 Subject: Part 2 of prior commit --- tdecore/network/ksocketaddress.cpp | 957 ----------------------------------- tdecore/network/ksocketaddress.h | 912 --------------------------------- tdecore/network/ksocketbase.cpp | 327 ------------ tdecore/network/ksocketbase.h | 771 ---------------------------- tdecore/network/ksocketbuffer.cpp | 329 ------------ tdecore/network/ksocketbuffer_p.h | 164 ------ tdecore/network/ksocketdevice.cpp | 891 -------------------------------- tdecore/network/ksocketdevice.h | 433 ---------------- tdecore/network/tdesocketaddress.cpp | 957 +++++++++++++++++++++++++++++++++++ tdecore/network/tdesocketaddress.h | 912 +++++++++++++++++++++++++++++++++ tdecore/network/tdesocketbase.cpp | 327 ++++++++++++ tdecore/network/tdesocketbase.h | 771 ++++++++++++++++++++++++++++ tdecore/network/tdesocketbuffer.cpp | 329 ++++++++++++ tdecore/network/tdesocketbuffer_p.h | 164 ++++++ tdecore/network/tdesocketdevice.cpp | 891 ++++++++++++++++++++++++++++++++ tdecore/network/tdesocketdevice.h | 433 ++++++++++++++++ 16 files changed, 4784 insertions(+), 4784 deletions(-) delete mode 100644 tdecore/network/ksocketaddress.cpp delete mode 100644 tdecore/network/ksocketaddress.h delete mode 100644 tdecore/network/ksocketbase.cpp delete mode 100644 tdecore/network/ksocketbase.h delete mode 100644 tdecore/network/ksocketbuffer.cpp delete mode 100644 tdecore/network/ksocketbuffer_p.h delete mode 100644 tdecore/network/ksocketdevice.cpp delete mode 100644 tdecore/network/ksocketdevice.h create mode 100644 tdecore/network/tdesocketaddress.cpp create mode 100644 tdecore/network/tdesocketaddress.h create mode 100644 tdecore/network/tdesocketbase.cpp create mode 100644 tdecore/network/tdesocketbase.h create mode 100644 tdecore/network/tdesocketbuffer.cpp create mode 100644 tdecore/network/tdesocketbuffer_p.h create mode 100644 tdecore/network/tdesocketdevice.cpp create mode 100644 tdecore/network/tdesocketdevice.h (limited to 'tdecore') diff --git a/tdecore/network/ksocketaddress.cpp b/tdecore/network/ksocketaddress.cpp deleted file mode 100644 index d1234044b..000000000 --- a/tdecore/network/ksocketaddress.cpp +++ /dev/null @@ -1,957 +0,0 @@ -/* -*- C++ -*- - * Copyright (C) 2003 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 "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "klocale.h" -#include "tdesocketaddress.h" - -#include "netsupp.h" - -using namespace KNetwork; - -#if 0 -class KIpAddress_localhostV4 : public KIpAddress -{ -public: - KIpAddress_localhostV4() - { - *m_data = htonl(0x7f000001); - m_version = 4; - } -}; - -class KIpAddress_localhostV6 : public KIpAddress -{ -public: - KIpAddress_localhostV6() - : KIpAddress(0L, 6) - { - m_data[3] = htonl(1); - } -}; -#endif - -static const char localhostV4_data[] = { 127, 0, 0, 1 }; -static const char localhostV6_data[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,1 }; - -const KIpAddress KIpAddress::localhostV4(&localhostV4_data, 4); -const KIpAddress KIpAddress::localhostV6(&localhostV6_data, 6); -const KIpAddress KIpAddress::anyhostV4(0L, 4); -const KIpAddress KIpAddress::anyhostV6(0L, 6); - -// helper function to test if an IPv6 v4-mapped address is equal to its IPv4 counterpart -static bool check_v4mapped(const TQ_UINT32* v6addr, TQ_UINT32 v4addr) -{ - // check that the v6 is a v4-mapped address - if (!(v6addr[0] == 0 && v6addr[1] == 0 && v6addr[2] == htonl(0x0000ffff))) - return false; // not a v4-mapped address - - return v6addr[3] == v4addr; -} - -// copy operator -KIpAddress& KIpAddress::operator =(const KIpAddress& other) -{ - m_version = other.m_version; - if (m_version == 4 || m_version == 6) - memcpy(m_data, other.m_data, sizeof(m_data)); - return *this; -} - -// comparison -bool KIpAddress::compare(const KIpAddress& other, bool checkMapped) const -{ - if (m_version == other.m_version) - switch (m_version) - { - case 0: - // both objects are empty - return true; - - case 4: - // IPv4 address - return *m_data == *other.m_data; - - case 6: - // IPv6 address - // they are 128-bit long, that is, 16 bytes - return memcmp(m_data, other.m_data, 16) == 0; - } - - if (checkMapped) - { - // check the possibility of a v4-mapped address being compared to an IPv4 one - if (m_version == 6 && other.m_version == 4 && check_v4mapped(m_data, *other.m_data)) - return true; - - if (other.m_version == 6 && m_version == 4 && check_v4mapped(other.m_data, *m_data)) - return true; - } - - return false; -} - -// sets the address to the given address -bool KIpAddress::setAddress(const TQString& address) -{ - m_version = 0; - - // try to guess the address version - if (address.find(':') != -1) - { -#ifdef AF_INET6 - // guessing IPv6 - - TQ_UINT32 buf[4]; - if (inet_pton(AF_INET6, address.latin1(), buf)) - { - memcpy(m_data, buf, sizeof(m_data)); - m_version = 6; - return true; - } -#endif - - return false; - } - else - { - TQ_UINT32 buf; - if (inet_pton(AF_INET, address.latin1(), &buf)) - { - *m_data = buf; - m_version = 4; - return true; - } - - return false; - } - - return false; // can never happen! -} - -bool KIpAddress::setAddress(const char* address) -{ - return setAddress(TQString::fromLatin1(address)); -} - -// set from binary data -bool KIpAddress::setAddress(const void* raw, int version) -{ - // this always succeeds - // except if version is invalid - if (version != 4 && version != 6) - return false; - - m_version = version; - if (raw != 0L) - memcpy(m_data, raw, version == 4 ? 4 : 16); - else - memset(m_data, 0, 16); - - return true; -} - -// presentation form -TQString KIpAddress::toString() const -{ - char buf[sizeof "1111:2222:3333:4444:5555:6666:255.255.255.255" + 2]; - buf[0] = '\0'; - switch (m_version) - { - case 4: - inet_ntop(AF_INET, m_data, buf, sizeof(buf) - 1); - return TQString::fromLatin1(buf); - - case 6: -#ifdef AF_INET6 - inet_ntop(AF_INET6, m_data, buf, sizeof(buf) - 1); -#endif - return TQString::fromLatin1(buf); - } - - return TQString::null; -} - -TQ_UINT32 KIpAddress::hostIPv4Addr(bool convertMapped) const -{ - TQ_UINT32 addr = IPv4Addr(convertMapped); - return ntohl(addr); -} - -/* - * An IPv6 socket address - * This is taken from RFC 2553. - */ -struct our_sockaddr_in6 -{ -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - TQ_UINT8 sin6_len; - TQ_UINT8 sin6_family; -# else //!HAVE_STRUCT_SOCKADDR_SA_LEN - TQ_UINT16 sin6_family; -# endif - TQ_UINT16 sin6_port; /* RFC says in_port_t */ - TQ_UINT32 sin6_flowinfo; - TQ_UINT8 sin6_addr[16]; // 24 bytes up to here - TQ_UINT32 sin6_scope_id; // 28 bytes total -}; - -// useful definitions -#define MIN_SOCKADDR_LEN sizeof(TQ_UINT16) -#define SOCKADDR_IN_LEN sizeof(sockaddr_in) -#define MIN_SOCKADDR_IN6_LEN ((unsigned long) &(((our_sockaddr_in6*)0)->sin6_scope_id)) -#define SOCKADDR_IN6_LEN sizeof(our_sockaddr_in6) -#define MIN_SOCKADDR_UN_LEN (sizeof(TQ_UINT16) + sizeof(char)) - - -class KNetwork::KSocketAddressData -{ -public: - /* - * Note: maybe this should be virtual - * But since the data is shared via the d pointer, it doesn't really matter - * what one class sees, so will the other - */ - class QMixSocketAddressRef : public KInetSocketAddress, public KUnixSocketAddress - { - public: - QMixSocketAddressRef(KSocketAddressData* d) - : KInetSocketAddress(d), KUnixSocketAddress(d) - { - } - }; - QMixSocketAddressRef ref; - - union - { - struct sockaddr *generic; - struct sockaddr_in *in; - struct our_sockaddr_in6 *in6; - struct sockaddr_un *un; - } addr; - TQ_UINT16 curlen, reallen; - - KSocketAddressData() - : ref(this) - { - addr.generic = 0L; - curlen = 0; - invalidate(); - } - - ~KSocketAddressData() - { - if (addr.generic != 0L) - free(addr.generic); - } - - inline bool invalid() const - { return reallen == 0; } - - inline void invalidate() - { reallen = 0; } - - void dup(const sockaddr* sa, TQ_UINT16 len, bool clear = true); - - void makeipv4() - { - short oldport = 0; - if (!invalid()) - switch (addr.generic->sa_family) - { - case AF_INET: - return; // nothing to do here -#ifdef AF_INET6 - case AF_INET6: - oldport = addr.in6->sin6_port; - break; -#endif - } - - // create new space - dup(0L, SOCKADDR_IN_LEN); - - addr.in->sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - addr.in->sin_len = SOCKADDR_IN_LEN; -#endif - addr.in->sin_port = oldport; - } - - void makeipv6() - { - short oldport = 0; - if (!invalid()) - switch (addr.generic->sa_family) - { - case AF_INET: - oldport = addr.in->sin_port; - break; - -#ifdef AF_INET6 - case AF_INET6: - return; // nothing to do here -#endif - } - - // make room - dup(0L, SOCKADDR_IN6_LEN); -#ifdef AF_INET6 - addr.in6->sin6_family = AF_INET6; -#endif -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - addr.in6->sin6_len = SOCKADDR_IN6_LEN; -#endif - addr.in6->sin6_port = oldport; - // sin6_scope_id and sin6_flowid are zero - } - -}; - -// create duplicates of -void KSocketAddressData::dup(const sockaddr* sa, TQ_UINT16 len, bool clear) -{ - if (len < MIN_SOCKADDR_LEN) - { - // certainly invalid - invalidate(); - return; - } - - if (sa && ((sa->sa_family == AF_INET && len < SOCKADDR_IN_LEN) || -#ifdef AF_INET6 - (sa->sa_family == AF_INET6 && len < MIN_SOCKADDR_IN6_LEN) || -#endif - (sa->sa_family == AF_UNIX && len < MIN_SOCKADDR_UN_LEN))) - { - // also invalid - invalidate(); - return; - } - - // good - reallen = len; - if (len > curlen) - { - if (len < 32) - curlen = 32; // big enough for sockaddr_in and sockaddr_in6 - else - curlen = len; - addr.generic = (sockaddr*)realloc(addr.generic, curlen); - } - - if (sa != 0L) - { - memcpy(addr.generic, sa, len); // copy - - // now, normalise the data - if (addr.generic->sa_family == AF_INET) - reallen = SOCKADDR_IN_LEN; // no need to be larger -#ifdef AF_INET6 - else if (addr.generic->sa_family == AF_INET6) - { - // set the extra field (sin6_scope_id) - - // the buffer is never smaller than 32 bytes, so this is always - // allowed - if (reallen < SOCKADDR_IN6_LEN) - addr.in6->sin6_scope_id = 0; - - reallen = SOCKADDR_IN6_LEN; - } -#endif - else if (addr.generic->sa_family == AF_UNIX) - reallen = MIN_SOCKADDR_UN_LEN + strlen(addr.un->sun_path); - } - else if (clear) - { - memset(addr.generic, 0, len); - addr.generic->sa_family = AF_UNSPEC; - } -} - -// default constructor -KSocketAddress::KSocketAddress() - : d(new KSocketAddressData) -{ -} - -// constructor from binary data -KSocketAddress::KSocketAddress(const sockaddr *sa, TQ_UINT16 len) - : d(new KSocketAddressData) -{ - setAddress(sa, len); -} - -KSocketAddress::KSocketAddress(const KSocketAddress& other) - : d(new(KSocketAddressData)) -{ - *this = other; -} - -KSocketAddress::KSocketAddress(KSocketAddressData *d2) - : d(d2) -{ -} - -KSocketAddress::~KSocketAddress() -{ - // prevent double-deletion, since we're already being deleted - if (d) - { - d->ref.KInetSocketAddress::d = 0L; - d->ref.KUnixSocketAddress::d = 0L; - delete d; - } -} - -KSocketAddress& KSocketAddress::operator =(const KSocketAddress& other) -{ - if (other.d && !other.d->invalid()) - d->dup(other.d->addr.generic, other.d->reallen); - else - d->invalidate(); - return *this; -} - -const sockaddr* KSocketAddress::address() const -{ - if (d->invalid()) - return 0L; - return d->addr.generic; -} - -sockaddr* KSocketAddress::address() -{ - if (d->invalid()) - return 0L; - return d->addr.generic; -} - -KSocketAddress& KSocketAddress::setAddress(const sockaddr* sa, TQ_UINT16 len) -{ - if (sa != 0L && len >= MIN_SOCKADDR_LEN) - d->dup(sa, len); - else - d->invalidate(); - - return *this; -} - -TQ_UINT16 KSocketAddress::length() const -{ - if (d->invalid()) - return 0; - return d->reallen; -} - -KSocketAddress& KSocketAddress::setLength(TQ_UINT16 len) -{ - d->dup((sockaddr*)0L, len, false); - - return *this; -} - -int KSocketAddress::family() const -{ - if (d->invalid()) - return AF_UNSPEC; - return d->addr.generic->sa_family; -} - -KSocketAddress& KSocketAddress::setFamily(int family) -{ - if (d->invalid()) - d->dup((sockaddr*)0L, MIN_SOCKADDR_LEN); - d->addr.generic->sa_family = family; - - return *this; -} - -bool KSocketAddress::operator ==(const KSocketAddress& other) const -{ - // if this is invalid, it's only equal if the other one is invalid as well - if (d->invalid()) - return other.d->invalid(); - - // check the family to make sure we don't do unnecessary comparison - if (d->addr.generic->sa_family != other.d->addr.generic->sa_family) - return false; // not the same family, not equal - - // same family then - // check the ones we know already - switch (d->addr.generic->sa_family) - { - case AF_INET: - Q_ASSERT(d->reallen == SOCKADDR_IN_LEN); - Q_ASSERT(other.d->reallen == SOCKADDR_IN_LEN); - return memcmp(d->addr.in, other.d->addr.in, SOCKADDR_IN_LEN) == 0; - -#ifdef AF_INET6 - case AF_INET6: - Q_ASSERT(d->reallen >= MIN_SOCKADDR_IN6_LEN); - Q_ASSERT(other.d->reallen >= MIN_SOCKADDR_IN6_LEN); - -# if !defined(HAVE_STRUCT_SOCKADDR_IN6) || defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID) - // check for the case where sin6_scope_id isn't present - if (d->reallen != other.d->reallen) - { - if (memcmp(d->addr.in6, other.d->addr.in6, MIN_SOCKADDR_IN6_LEN) != 0) - return false; // not equal - if (d->reallen > other.d->reallen) - return d->addr.in6->sin6_scope_id == 0; - else - return other.d->addr.in6->sin6_scope_id == 0; - } -# endif - - return memcmp(d->addr.in6, other.d->addr.in6, d->reallen) == 0; -#endif - - case AF_UNIX: - Q_ASSERT(d->reallen >= MIN_SOCKADDR_UN_LEN); - Q_ASSERT(other.d->reallen >= MIN_SOCKADDR_UN_LEN); - - // do a string comparison here - return strcmp(d->addr.un->sun_path, other.d->addr.un->sun_path) == 0; - - default: - // something else we don't know about - // they are equal if and only if they are exactly equal - if (d->reallen == other.d->reallen) - return memcmp(d->addr.generic, other.d->addr.generic, d->reallen) == 0; - } - - return false; // not equal in any other case -} - -TQString KSocketAddress::nodeName() const -{ - if (d->invalid()) - return TQString::null; - - switch (d->addr.generic->sa_family) - { - case AF_INET: -#ifdef AF_INET6 - case AF_INET6: - - TQString scopeid("%"); - if (d->addr.generic->sa_family == AF_INET6 && d->addr.in6->sin6_scope_id) - scopeid += TQString::number(d->addr.in6->sin6_scope_id); - else - scopeid.truncate(0); - return d->ref.ipAddress().toString() + scopeid; -#else - return d->ref.ipAddress().toString(); -#endif - } - - // any other case, including AF_UNIX - return TQString::null; -} - -TQString KSocketAddress::serviceName() const -{ - if (d->invalid()) - return TQString::null; - - switch (d->addr.generic->sa_family) - { - case AF_INET: -#ifdef AF_INET6 - case AF_INET6: -#endif - return TQString::number(d->ref.port()); - - case AF_UNIX: - return d->ref.pathname(); - } - - return TQString::null; -} - -TQString KSocketAddress::toString() const -{ - if (d->invalid()) - return TQString::null; - - TQString fmt; - - if (d->addr.generic->sa_family == AF_INET) - fmt = "%1:%2"; -#ifdef AF_INET6 - else if (d->addr.generic->sa_family == AF_INET6) - fmt = "[%1]:%2"; -#endif - else if (d->addr.generic->sa_family == AF_UNIX) - return TQString::fromLatin1("unix:%1").arg(serviceName()); - else - return i18n("1: the unknown socket address family number", - "Unknown family %1").arg(d->addr.generic->sa_family); - - return fmt.arg(nodeName()).arg(serviceName()); -} - -KInetSocketAddress& KSocketAddress::asInet() -{ - return d->ref; -} - -KInetSocketAddress KSocketAddress::asInet() const -{ - return d->ref; -} - -KUnixSocketAddress& KSocketAddress::asUnix() -{ - return d->ref; -} - -KUnixSocketAddress KSocketAddress::asUnix() const -{ - return d->ref; -} - -int KSocketAddress::ianaFamily(int af) -{ - switch (af) - { - case AF_INET: - return 1; - -#ifdef AF_INET6 - case AF_INET6: - return 2; -#endif - - default: - return 0; - } -} - -int KSocketAddress::fromIanaFamily(int iana) -{ - switch (iana) - { - case 1: - return AF_INET; - -#ifdef AF_INET6 - case 2: - return AF_INET6; -#endif - - default: - return AF_UNSPEC; - } -} - -// default constructor -KInetSocketAddress::KInetSocketAddress() -{ -} - -// binary data constructor -KInetSocketAddress::KInetSocketAddress(const sockaddr* sa, TQ_UINT16 len) - : KSocketAddress(sa, len) -{ - if (!d->invalid()) - update(); -} - -// create from IP and port -KInetSocketAddress::KInetSocketAddress(const KIpAddress& host, TQ_UINT16 port) -{ - setHost(host); - setPort(port); -} - -// copy constructor -KInetSocketAddress::KInetSocketAddress(const KInetSocketAddress& other) - : KSocketAddress(other) -{ -} - -// special copy constructor -KInetSocketAddress::KInetSocketAddress(const KSocketAddress& other) - : KSocketAddress(other) -{ - if (!d->invalid()) - update(); -} - -// special constructor -KInetSocketAddress::KInetSocketAddress(KSocketAddressData *d) - : KSocketAddress(d) -{ -} - -// destructor -KInetSocketAddress::~KInetSocketAddress() -{ - /* nothing to do */ -} - -// copy operator -KInetSocketAddress& KInetSocketAddress::operator =(const KInetSocketAddress& other) -{ - KSocketAddress::operator =(other); - return *this; -} - -// IP version -int KInetSocketAddress::ipVersion() const -{ - if (d->invalid()) - return 0; - - switch (d->addr.generic->sa_family) - { - case AF_INET: - return 4; - -#ifdef AF_INET6 - case AF_INET6: - return 6; -#endif - } - - return 0; // for all other cases -} - -KIpAddress KInetSocketAddress::ipAddress() const -{ - if (d->invalid()) - return KIpAddress(); // return an empty address as well - - switch (d->addr.generic->sa_family) - { - case AF_INET: - return KIpAddress(&d->addr.in->sin_addr, 4); -#ifdef AF_INET6 - case AF_INET6: - return KIpAddress(&d->addr.in6->sin6_addr, 6); -#endif - } - - return KIpAddress(); // empty in all other cases -} - -KInetSocketAddress& KInetSocketAddress::setHost(const KIpAddress& ip) -{ - switch (ip.version()) - { - case 4: - makeIPv4(); - memcpy(&d->addr.in->sin_addr, ip.addr(), sizeof(d->addr.in->sin_addr)); - break; - - case 6: - makeIPv6(); - memcpy(&d->addr.in6->sin6_addr, ip.addr(), sizeof(d->addr.in6->sin6_addr)); - break; - - default: - // empty - d->invalidate(); - } - - return *this; -} - -// returns the port -TQ_UINT16 KInetSocketAddress::port() const -{ - if (d->invalid()) - return 0; - - switch (d->addr.generic->sa_family) - { - case AF_INET: - return ntohs(d->addr.in->sin_port); - -#ifdef AF_INET6 - case AF_INET6: - return ntohs(d->addr.in6->sin6_port); -#endif - } - - return 0; -} - -KInetSocketAddress& KInetSocketAddress::setPort(TQ_UINT16 port) -{ - if (d->invalid()) - makeIPv4(); - - switch (d->addr.generic->sa_family) - { - case AF_INET: - d->addr.in->sin_port = htons(port); - break; - -#ifdef AF_INET6 - case AF_INET6: - d->addr.in6->sin6_port = htons(port); - break; -#endif - - default: - d->invalidate(); // setting the port on something else - } - - return *this; -} - -KInetSocketAddress& KInetSocketAddress::makeIPv4() -{ - d->makeipv4(); - return *this; -} - -KInetSocketAddress& KInetSocketAddress::makeIPv6() -{ - d->makeipv6(); - return *this; -} - -TQ_UINT32 KInetSocketAddress::flowinfo() const -{ -#ifndef AF_INET6 - return 0; -#else - - if (!d->invalid() && d->addr.in6->sin6_family == AF_INET6) - return d->addr.in6->sin6_flowinfo; - return 0; -#endif -} - -KInetSocketAddress& KInetSocketAddress::setFlowinfo(TQ_UINT32 flowinfo) -{ - makeIPv6(); // must set here - d->addr.in6->sin6_flowinfo = flowinfo; - return *this; -} - -int KInetSocketAddress::scopeId() const -{ -#ifndef AF_INET6 - return 0; -#else - - if (!d->invalid() && d->addr.in6->sin6_family == AF_INET6) - return d->addr.in6->sin6_scope_id; - return 0; -#endif -} - -KInetSocketAddress& KInetSocketAddress::setScopeId(int scopeid) -{ - makeIPv6(); // must set here - d->addr.in6->sin6_scope_id = scopeid; - return *this; -} - -void KInetSocketAddress::update() -{ - if (d->addr.generic->sa_family == AF_INET) - return; -#ifdef AF_INET6 - else if (d->addr.generic->sa_family == AF_INET6) - return; -#endif - else - d->invalidate(); -} - -KUnixSocketAddress::KUnixSocketAddress() -{ -} - -KUnixSocketAddress::KUnixSocketAddress(const sockaddr* sa, TQ_UINT16 len) - : KSocketAddress(sa, len) -{ - if (!d->invalid() && d->addr.un->sun_family != AF_UNIX) - d->invalidate(); -} - -KUnixSocketAddress::KUnixSocketAddress(const KUnixSocketAddress& other) - : KSocketAddress(other) -{ -} - -KUnixSocketAddress::KUnixSocketAddress(const TQString& pathname) -{ - setPathname(pathname); -} - -KUnixSocketAddress::KUnixSocketAddress(KSocketAddressData* d) - : KSocketAddress(d) -{ -} - -KUnixSocketAddress::~KUnixSocketAddress() -{ -} - -KUnixSocketAddress& KUnixSocketAddress::operator =(const KUnixSocketAddress& other) -{ - KSocketAddress::operator =(other); - return *this; -} - -TQString KUnixSocketAddress::pathname() const -{ - if (!d->invalid() && d->addr.un->sun_family == AF_UNIX) - return TQFile::decodeName(d->addr.un->sun_path); - return TQString::null; -} - -KUnixSocketAddress& KUnixSocketAddress::setPathname(const TQString& path) -{ - d->dup(0L, MIN_SOCKADDR_UN_LEN + path.length()); - d->addr.un->sun_family = AF_UNIX; - strcpy(d->addr.un->sun_path, TQFile::encodeName(path)); - -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - d->addr.un->sun_len = d->reallen; -#endif - - return *this; -} diff --git a/tdecore/network/ksocketaddress.h b/tdecore/network/ksocketaddress.h deleted file mode 100644 index 885bb77cb..000000000 --- a/tdecore/network/ksocketaddress.h +++ /dev/null @@ -1,912 +0,0 @@ -/* -*- C++ -*- - * Copyright (C) 2003 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. - */ - -#ifndef TDESOCKETADDRESS_H -#define TDESOCKETADDRESS_H - -#include -#include - -#include - -struct sockaddr; -struct sockaddr_in; -struct sockaddr_in6; -struct sockaddr_un; - -namespace KNetwork { - -class KIpAddress; -class KSocketAddress; -class KInetSocketAddress; -class KUnixSocketAddress; - -/** @class KIpAddress tdesocketaddress.h tdesocketaddress.h - * @brief An IP address. - * - * This class represents one IP address, version 4 or 6. This is only - * the address, not including port information or other data. - * - * It is not a good programming practice to create address from objects - * like this. Instead, prefer a more thorough function like - * @ref KResolver::resolve, which also handle extra information like scope - * ids. - * - * This is a light-weight class. Most of the member functions are inlined and - * there are no virtual functions. This object's size should be less than 20 - * bytes. Also note that there is no sharing of data. - * - * @author Thiago Macieira - */ -class TDECORE_EXPORT KIpAddress -{ -public: - /** - * Default constructor. Creates an empty address. - * It defaults to IP version 4. - */ - inline KIpAddress() : m_version(0) - { } - - /** - * Copy constructor. Copies the data from the other - * object. - * - * Data is not shared. - * - * @param other the other - */ - inline KIpAddress(const KIpAddress& other) - { *this = other; } - - /** - * Creates an object from the given string representation. - * - * The IP version is guessed from the address format. - * - * @param addr the address - */ - inline KIpAddress(const TQString& addr) - { setAddress(addr); } - - /** - * Creates an object from the given string representation. - * - * The IP version is guessed from the address format. - * - * @param addr the address - */ - inline KIpAddress(const char* addr) - { setAddress(addr); } - - /** - * Creates an object from the given raw data and IP version. - * - * @param addr the raw data - * @param version the IP version (4 or 6) - */ - inline KIpAddress(const void* addr, int version = 4) - { setAddress(addr, version); } - - /** - * This is a convenience constructor. Constructs an object - * from the given IPv4 address in the form of an integer. - * - * Note: do not write code to depend on IPv4 addresses being - * integer types. Instead, treat them as a special type, like - * a KIpAddress or the system's in_addr. - * - * @param ip4addr the IPv4 address - */ - inline KIpAddress(TQ_UINT32 ip4addr) - { setAddress(&ip4addr, 4); } - - /** - * Destructor. This frees resources associated with this object. - * - * Note: destructor is non-virtual. The compiler will happily optimise it - * out of the way. - */ - inline ~KIpAddress() - { } - - /** - * Copy operator. - * - * Copies the data from the other object into this one. - * - * @param other the object to copy - */ - KIpAddress& operator =(const KIpAddress& other); - - /** - * Returns true if the two addresses match. - * This function performs a v4-mapped check. - * @see compare - */ - inline bool operator ==(const KIpAddress& other) const - { return compare(other, true); } - - /** - * Compares this address against the other, supplied one and return - * true if they match. The @p checkMapped parameter controls whether - * a check for an IPv6 v4-mapped address will be performed. - * - * An IPv6 v4-mapped address is an IPv6 address that is, for all purposes, - * equivalent to an IPv4 one. The default behaviour of this function - * is to take that into account. If you want a strict matching, - * pass @b false to the @p checkMapped parameter. - * - * @param other the other IP address - * @param checkMapped whether v4-mapped addresses will be taken into account - */ - bool compare(const KIpAddress& other, bool checkMapped = true) const; - - /** - * Retrieves the IP version in this object. - * - * @returns the version: 4 or 6 - */ - inline int version() const - { return m_version; } - - /** - * Returns true if this is an IPv4 address. - */ - inline bool isIPv4Addr() const - { return version() == 4; } - - /** - * Returns true if this is an IPv6 address. - */ - inline bool isIPv6Addr() const - { return version() == 6; } - - /** - * Sets the address to the given string representation. - * - * @return true if the address was successfully parsed; otherwise returns - * false and leaves the object unchanged. - */ - bool setAddress(const TQString& address); - - /** - * Sets the address to the given string representation. - * - * @return true if the address was successfully parsed; otherwise returns - * false and leaves the object unchanged. - */ - bool setAddress(const char* address); - - /** - * Sets the address to the given raw binary representation. - * - * @param raw a pointer to the raw binary data - * @param version the IP version - * @return true if the address was successfully parsed; otherwise returns - * false and leaves the object unchanged. - */ - bool setAddress(const void* raw, int version = 4); - - /** - * Returns the address as a string. - */ - TQString toString() const; - - /** - * Returns a pointer to binary raw data representing the address. - */ - inline const void *addr() const - { return m_data; } - - /** - * This is a convenience function. Returns the IPv4 address in a - * 32-bit integer. The result is only valid if @ref isIPv4Addr returns - * true. Alternatively, if the contained IPv6 address is a v4-mapped one - * and the @p convertMapped parameter is true, the result will also be - * valid. The address returned is in network byte order. - * - * Note: you should not treat IP addresses as integers. Instead, - * use types defined for that purpose, such as KIpAddress or the - * system's in_addr type. - * - */ - inline TQ_UINT32 IPv4Addr(bool convertMapped = true) const - { - return (convertMapped && isV4Mapped()) ? m_data[3] : m_data[0]; - } - - /** - * This is a convenience function. Returns the IPv4 address in a - * 32-bit integer. The result is only valid if @ref isIPv4Addr returns - * true. Alternatively, if the contained IPv6 address is a v4-mapped one - * and the @p convertMapped parameter is true, the result will also be - * valid. The address returned is in host byte order. - * - */ - TQ_UINT32 hostIPv4Addr(bool convertMapped = true) const; - -public: - /*-- tests --*/ - - /** - * Returns true if this is the IPv4 or IPv6 unspecified address. - */ - inline bool isUnspecified() const - { return version() == 0 ? true : (*this == anyhostV4 || *this == anyhostV6); } - - /** - * Returns true if this is either the IPv4 or the IPv6 localhost address. - */ - inline bool isLocalhost() const - { return version() == 0 ? false : (*this == localhostV4 || *this == localhostV6); } - - /** - * This is an alias for @ref isLocalhost. - */ - inline bool isLoopback() const - { return isLocalhost(); } - - /** - * Returns true if this is an IPv4 class A address, i.e., - * from 0.0.0.0 to 127.255.255.255. - * - * This function does not test for v4-mapped addresses. - */ - inline bool isClassA() const - { return version() != 4 ? false : (hostIPv4Addr() & 0x80000000) == 0; } - - /** - * Returns true if this is an IPv4 class B address, i.e., one from - * 128.0.0.0 to 191.255.255.255. - * - * This function does not test for v4-mapped addresses. - */ - inline bool isClassB() const - { return version() != 4 ? false : (hostIPv4Addr() & 0xc0000000) == 0x80000000; } - - /** - * Returns true if this is an IPv4 class C address, i.e., one from - * 192.0.0.0 to 223.255.255.255. - * - * This function does not test for v4-mapped addresses. - */ - inline bool isClassC() const - { return version() != 4 ? false : (hostIPv4Addr() & 0xe0000000) == 0xc0000000; } - - /** - * Returns true if this is an IPv4 class D (a.k.a. multicast) address. - * - * Note: this function is not the same as @ref isMulticast. isMulticast also - * tests for IPv6 multicast addresses. - */ - inline bool isClassD() const - { return version() != 4 ? false : (hostIPv4Addr() & 0xf0000000) == 0xe0000000; } - - /** - * Returns true if this is a multicast address, be it IPv4 or IPv6. - */ - inline bool isMulticast() const - { - if (version() == 4) return isClassD(); - if (version() == 6) return ((TQ_UINT8*)addr())[0] == 0xff; - return false; - } - - /** - * Returns true if this is an IPv6 link-local address. - */ - inline bool isLinkLocal() const - { - if (version() != 6) return false; - TQ_UINT8* addr = (TQ_UINT8*)this->addr(); - return (addr[0] & 0xff) == 0xfe && - (addr[1] & 0xc0) == 0x80; - } - - /** - * Returns true if this is an IPv6 site-local address. - */ - inline bool isSiteLocal() const - { - if (version() != 6) return false; - TQ_UINT8* addr = (TQ_UINT8*)this->addr(); - return (addr[0] & 0xff) == 0xfe && - (addr[1] & 0xc0) == 0xc0; - } - - /** - * Returns true if this is a global IPv6 address. - */ - inline bool isGlobal() const - { return version() != 6 ? false : !(isMulticast() || isLinkLocal() || isSiteLocal()); } - - /** - * Returns true if this is a v4-mapped IPv6 address. - */ - inline bool isV4Mapped() const - { - if (version() != 6) return false; - TQ_UINT32* addr = (TQ_UINT32*)this->addr(); - return addr[0] == 0 && addr[1] == 0 && - ((TQ_UINT16*)&addr[2])[0] == 0 && - ((TQ_UINT16*)&addr[2])[1] == 0xffff; - } - - /** - * Returns true if this is a v4-compat IPv6 address. - */ - inline bool isV4Compat() const - { - if (version() != 6 || isLocalhost()) return false; - TQ_UINT32* addr = (TQ_UINT32*)this->addr(); - return addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] != 0; - } - - /** - * Returns true if this is an IPv6 node-local multicast address. - */ - inline bool isMulticastNodeLocal() const - { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0x1; } - - /** - * Returns true if this is an IPv6 link-local multicast address. - */ - inline bool isMulticastLinkLocal() const - { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0x2; } - - /** - * Returns true if this is an IPv6 site-local multicast address. - */ - inline bool isMulticastSiteLocal() const - { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0x5; } - - /** - * Returns true if this is an IPv6 organisational-local multicast address. - */ - inline bool isMulticastOrgLocal() const - { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0x8; } - - /** - * Returns true if this is an IPv6 global multicast address. - */ - inline bool isMulticastGlobal() const - { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0xe; } - -protected: - TQ_UINT32 m_data[4]; // 16 bytes, needed for an IPv6 address - - char m_version; - -public: - /// localhost in IPv4 (127.0.0.1) - static const KIpAddress localhostV4; - /// the any host or undefined address in IPv4 (0.0.0.0) - static const KIpAddress anyhostV4; - - /// localhost in IPv6 (::1) - static const KIpAddress localhostV6; - /// the any host or undefined address in IPv6 (::) - static const KIpAddress anyhostV6; -}; - - -class KSocketAddressData; -/** @class KSocketAddress tdesocketaddress.h tdesocketaddress.h - * @brief A generic socket address. - * - * This class holds one generic socket address. - * - * @author Thiago Macieira - */ -class TDECORE_EXPORT KSocketAddress -{ -public: - /** - * Default constructor. - * - * Creates an empty object - */ - KSocketAddress(); - - /** - * Creates this object with the given data. - * The raw socket address is copied into this object. - * - * @param sa the socket address structure - * @param len the socket address length - */ - KSocketAddress(const sockaddr* sa, TQ_UINT16 len); - - /** - * Copy constructor. This creates a copy of the other - * object. - * - * Data is not shared. - * - * @param other the object to copy from - */ - KSocketAddress(const KSocketAddress& other); - - /** - * Destructor. Frees any associated resources. - */ - virtual ~KSocketAddress(); - - /** - * Performs a shallow copy of the other object into this one. - * Data will be copied. - * - * @param other the object to copy from - */ - KSocketAddress& operator =(const KSocketAddress& other); - - /** - * Returns the socket address structure, to be passed down to - * low level functions. - * - * Note that this function returns NULL for invalid or empty sockets, - * so you may use to to test for validity. - */ - const sockaddr* address() const; - - /** - * Returns the socket address structure, to be passed down to - * low level functions. - * - * Note that this function returns NULL for invalid or empty sockets, - * so you may use to to test for validity. - * - * The returned value, if not NULL, is an internal buffer which is guaranteed - * to be at least @ref length() bytes long. - */ - sockaddr* address(); - - /** - * Sets the address to the given address. - * The raw socket address is copied into this object. - * - * @param sa the socket address structure - * @param len the socket address length - */ - KSocketAddress& setAddress(const sockaddr *sa, TQ_UINT16 len); - - /** - * Returns the socket address structure, to be passed down to - * low level functions. - */ - inline operator const sockaddr*() const - { return address(); } - - /** - * Returns the length of this socket address structure. - */ - TQ_UINT16 length() const; - - /** - * Sets the length of this socket structure. - * - * Use this function with care. It allows you to resize the internal - * buffer to fit needs. This function should not be used except for handling - * unknown socket address structures. - * - * Also note that this function may invalidate the socket if a known - * family is set (Internet or Unix socket) and the new length would be - * too small to hold the system's sockaddr_* structure. If unsure, reset - * the family: - * - * \code - * KSocketAddress qsa; - * [...] - * qsa.setFamily(AF_UNSPEC).setLength(newlen); - * \endcode - * - * @param len the new length - */ - KSocketAddress& setLength(TQ_UINT16 len); - - /** - * Returns the family of this address. - * @return the family of this address, AF_UNSPEC if it's undefined - */ - int family() const; - - /** - * Sets the family of this object. - * - * Note: setting the family will probably invalidate any address data - * contained in this object. Use this function with care. - * - * @param family the new family to set - */ - virtual KSocketAddress& setFamily(int family); - - /** - * Returns the IANA family number of this address. - * @return the IANA family number of this address (1 for AF_INET. - * 2 for AF_INET6, otherwise 0) - */ - inline int ianaFamily() const - { return ianaFamily(family()); } - - /** - * Returns true if this equals the other socket. - * - * Socket addresses are considered matching if and only if all data is the same. - * - * @param other the other socket - * @return true if both sockets are equal - */ - bool operator ==(const KSocketAddress& other) const; - - /** - * Returns the node name of this socket. - * - * In the case of Internet sockets, this is string representation of the IP address. - * The default implementation returns TQString::null. - * - * @return the node name, can be TQString::null - * @bug use KResolver to resolve unknown families - */ - virtual TQString nodeName() const; - - /** - * Returns the service name for this socket. - * - * In the case of Internet sockets, this is the port number. - * The default implementation returns TQString::null. - * - * @return the service name, can be TQString::null - * @bug use KResolver to resolve unknown families - */ - virtual TQString serviceName() const; - - /** - * Returns this socket address as a string suitable for - * printing. Family, node and service are part of this address. - * - * @bug use KResolver to resolve unknown families - */ - virtual TQString toString() const; - - /** - * Returns an object reference that can be used to manipulate this socket - * as an Internet socket address. Both objects share the same data. - */ - KInetSocketAddress& asInet(); - - /** - * Returns an object is equal to this object's data, but they don't share it. - */ - KInetSocketAddress asInet() const; - - /** - * Returns an object reference that can be used to manipulate this socket - * as a Unix socket address. Both objects share the same data. - */ - KUnixSocketAddress& asUnix(); - - /** - * Returns an object is equal to this object's data, but they don't share it. - */ - KUnixSocketAddress asUnix() const; - -protected: - /// @internal - /// private data - KSocketAddressData *d; - - /// @internal - /// extra constructor - KSocketAddress(KSocketAddressData* d); - -public: // static - /** - * Returns the IANA family number of the given address family. - * Returns 0 if there is no corresponding IANA family number. - * @param af the address family, in AF_* constants - * @return the IANA family number of this address (1 for AF_INET. - * 2 for AF_INET6, otherwise 0) - */ - static int ianaFamily(int af); - - /** - * Returns the address family of the given IANA family number. - * @return the address family, AF_UNSPEC for unknown IANA family numbers - */ - static int fromIanaFamily(int iana); -}; - - -/** @class KInetSocketAddress tdesocketaddress.h tdesocketaddress.h - * @brief an Internet socket address - * - * An Inet (IPv4 or IPv6) socket address - * - * This is an IPv4 or IPv6 address of the Internet. - * - * @author Thiago Macieira - */ -class TDECORE_EXPORT KInetSocketAddress: public KSocketAddress -{ - friend class KSocketAddress; -public: - /** - * Public constructor. Creates an empty object. - */ - KInetSocketAddress(); - - /** - * Creates an object from raw data. - * - * Note: if the socket address @p sa does not contain a valid Internet - * socket (IPv4 or IPv6), this object will be empty. - * - * @param sa the sockaddr structure - * @param len the structure's length - */ - KInetSocketAddress(const sockaddr* sa, TQ_UINT16 len); - - /** - * Creates an object from an IP address and port. - * - * @param host the IP address - * @param port the port number - */ - KInetSocketAddress(const KIpAddress& host, TQ_UINT16 port); - - /** - * Copy constructor. - * - * Data is not shared. - * - * @param other the other object - */ - KInetSocketAddress(const KInetSocketAddress& other); - - /** - * Copy constructor. - * - * If the other, generic socket address contains an Internet address, - * it will be copied. Otherwise, this object will be empty. - * - * @param other the other object - */ - KInetSocketAddress(const KSocketAddress& other); - - /** - * Destroys this object. - */ - virtual ~KInetSocketAddress(); - - /** - * Copy operator. - * - * Copies the other object into this one. - * - * @param other the other object - */ - KInetSocketAddress& operator =(const KInetSocketAddress& other); - - /** - * Cast operator to sockaddr_in. - */ - inline operator const sockaddr_in*() const - { return (const sockaddr_in*)address(); } - - /** - * Cast operator to sockaddr_in6. - */ - inline operator const sockaddr_in6*() const - { return (const sockaddr_in6*)address(); } - - /** - * Returns the IP version of the address this object holds. - * - * @return 4 or 6, if IPv4 or IPv6, respectively; 0 if this object is empty - */ - int ipVersion() const; - - /** - * Returns the IP address component. - */ - KIpAddress ipAddress() const; - - /** - * Sets the IP address to the given raw address. - * - * This call will preserve port numbers accross IP versions, but will lose - * IPv6 specific data if the address is set to IPv4. - * - * @param addr the address to set to - * @return a reference to itself - */ - KInetSocketAddress& setHost(const KIpAddress& addr); - - /** - * Retrieves the port number stored in this object. - * - * @return a port number in the range 0 to 65535, inclusive. An empty or - * invalid object will have a port number of 0. - */ - TQ_UINT16 port() const; - - /** - * Sets the port number. If this object is empty, this function will default to - * creating an IPv4 address. - * - * @param port the port number to set - * @return a reference to itself - */ - KInetSocketAddress& setPort(TQ_UINT16 port); - - /** - * Converts this object to an IPv4 socket address. It has no effect if the object - * is already an IPv4 socket address. - * - * If this object is an IPv6 address, the port number is preserved. All other information - * is lost. - * - * @return a reference to itself - */ - KInetSocketAddress& makeIPv4(); - - /** - * Converts this object to an IPv6 socket address. It has no effect if the object - * is already an IPv6 socket address. - * - * If this object is an IPv4 address, the port number is preserved. - * - * @return a reference to itself - */ - KInetSocketAddress& makeIPv6(); - - /** - * Returns the flowinfo information from the IPv6 socket address. - * - * @return the flowinfo information or 0 if this object is empty or IPv4 - */ - TQ_UINT32 flowinfo() const; - - /** - * Sets the flowinfo information for an IPv6 socket address. If this is not - * an IPv6 socket address, this function converts it to one. See makeIPv6. - * - * @param flowinfo the flowinfo to set - * @return a reference to itself - */ - KInetSocketAddress& setFlowinfo(TQ_UINT32 flowinfo); - - /** - * Returns the scope id this IPv6 socket is bound to. - * - * @return the scope id, or 0 if this is not an IPv6 object - */ - int scopeId() const; - - /** - * Sets the scope id for this IPv6 object. If this is not an IPv6 socket - * address, this function converts it to one. See makeIPv6 - * - * @param scopeid the scopeid to set - * @return a reference to itself - */ - KInetSocketAddress& setScopeId(int scopeid); - -protected: - /// @internal - /// extra constructor - KInetSocketAddress(KSocketAddressData* d); - -private: - void update(); -}; - -/* - * External definition - */ - -/** @class KUnixSocketAddress tdesocketaddress.h tdesocketaddress.h - * @brief A Unix (local) socket address. - * - * This is a Unix socket address. - * - * Note that this class uses QStrings to represent filenames, which means - * the proper encoding is used to translate into valid filesystem file names. - * - * @author Thiago Macieira - */ -class TDECORE_EXPORT KUnixSocketAddress: public KSocketAddress -{ - friend class KSocketAddress; -public: - /** - * Default constructor. Creates an empty object. - */ - KUnixSocketAddress(); - - /** - * Creates this object with the given raw data. If - * the sockaddr structure does not contain a Local namespace - * (Unix) socket, this object will be created empty. - * - * @param sa the socket address structure - * @param len the structure's length - */ - KUnixSocketAddress(const sockaddr* sa, TQ_UINT16 len); - - /** - * Copy constructor. Creates a copy of the other object, - * sharing the data explicitly. - * - * @param other the other object - */ - KUnixSocketAddress(const KUnixSocketAddress& other); - - /** - * Constructs an object from the given pathname. - */ - KUnixSocketAddress(const TQString& pathname); - - /** - * Destructor. - */ - virtual ~KUnixSocketAddress(); - - /** - * Copy operator. Copies the contents of the other object into - * this one. Data is explicitly shared. - * - * @param other the other - */ - KUnixSocketAddress& operator =(const KUnixSocketAddress& other); - - /** - * Cast operator to sockaddr_un. - */ - inline operator const sockaddr_un*() const - { return (const sockaddr_un*)address(); } - - /** - * Returns the pathname associated with this object. Will return - * TQString::null if this object is empty. - */ - TQString pathname() const; - - /** - * Sets the pathname for the object. - * - * @return a reference to itself - */ - KUnixSocketAddress& setPathname(const TQString& path); - -protected: - /// @internal - /// extra constructor - KUnixSocketAddress(KSocketAddressData* d); -}; - -} // namespace KNetwork - -#endif diff --git a/tdecore/network/ksocketbase.cpp b/tdecore/network/ksocketbase.cpp deleted file mode 100644 index 9be0d6e52..000000000 --- a/tdecore/network/ksocketbase.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* -*- 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. - */ - -#include -#include -#include "klocale.h" - -#include "tdesocketbase.h" -#include "tdesocketdevice.h" - -using namespace KNetwork; - -class KNetwork::KSocketBasePrivate -{ -public: - int socketOptions; - int socketError; - int capabilities; - - mutable KSocketDevice* device; - - TQMutex mutex; - - KSocketBasePrivate() - : mutex(true) // create recursive - { } -}; - -KSocketBase::KSocketBase() - : d(new KSocketBasePrivate) -{ - d->socketOptions = Blocking; - d->socketError = 0; - d->device = 0L; - d->capabilities = 0; -} - -KSocketBase::~KSocketBase() -{ - delete d->device; - delete d; -} - -bool KSocketBase::setSocketOptions(int opts) -{ - d->socketOptions = opts; - return true; -} - -int KSocketBase::socketOptions() const -{ - return d->socketOptions; -} - -bool KSocketBase::setBlocking(bool enable) -{ - return setSocketOptions((socketOptions() & ~Blocking) | (enable ? Blocking : 0)); -} - -bool KSocketBase::blocking() const -{ - return socketOptions() & Blocking; -} - -bool KSocketBase::setAddressReuseable(bool enable) -{ - return setSocketOptions((socketOptions() & ~AddressReuseable) | (enable ? AddressReuseable : 0)); -} - -bool KSocketBase::addressReuseable() const -{ - return socketOptions() & AddressReuseable; -} - -bool KSocketBase::setIPv6Only(bool enable) -{ - return setSocketOptions((socketOptions() & ~IPv6Only) | (enable ? IPv6Only : 0)); -} - -bool KSocketBase::isIPv6Only() const -{ - return socketOptions() & IPv6Only; -} - -bool KSocketBase::setBroadcast(bool enable) -{ - return setSocketOptions((socketOptions() & ~Broadcast) | (enable ? Broadcast : 0)); -} - -bool KSocketBase::broadcast() const -{ - return socketOptions() & Broadcast; -} - -KSocketDevice* KSocketBase::socketDevice() const -{ - if (d->device) - return d->device; - - // it doesn't exist, so create it - TQMutexLocker locker(mutex()); - if (d->device) - return d->device; - - KSocketBase* that = const_cast(this); - KSocketDevice* dev = 0; - if (d->capabilities) - dev = KSocketDevice::createDefault(that, d->capabilities); - if (!dev) - dev = KSocketDevice::createDefault(that); - that->setSocketDevice(dev); - return d->device; -} - -void KSocketBase::setSocketDevice(KSocketDevice* device) -{ - TQMutexLocker locker(mutex()); - if (d->device == 0L) - d->device = device; -} - -int KSocketBase::setRequestedCapabilities(int add, int remove) -{ - d->capabilities |= add; - d->capabilities &= ~remove; - return d->capabilities; -} - -bool KSocketBase::hasDevice() const -{ - return d->device != 0L; -} - -void KSocketBase::setError(SocketError error) -{ - d->socketError = error; -} - -KSocketBase::SocketError KSocketBase::error() const -{ - return static_cast(d->socketError); -} - -// static -TQString KSocketBase::errorString(KSocketBase::SocketError code) -{ - TQString reason; - switch (code) - { - case NoError: - reason = i18n("Socket error code NoError", "no error"); - break; - - case LookupFailure: - reason = i18n("Socket error code LookupFailure", - "name lookup has failed"); - break; - - case AddressInUse: - reason = i18n("Socket error code AddressInUse", - "address already in use"); - break; - - case AlreadyBound: - reason = i18n("Socket error code AlreadyBound", - "socket is already bound"); - break; - - case AlreadyCreated: - reason = i18n("Socket error code AlreadyCreated", - "socket is already created"); - break; - - case NotBound: - reason = i18n("Socket error code NotBound", - "socket is not bound"); - break; - - case NotCreated: - reason = i18n("Socket error code NotCreated", - "socket has not been created"); - break; - - case WouldBlock: - reason = i18n("Socket error code WouldBlock", - "operation would block"); - break; - - case ConnectionRefused: - reason = i18n("Socket error code ConnectionRefused", - "connection actively refused"); - break; - - case ConnectionTimedOut: - reason = i18n("Socket error code ConnectionTimedOut", - "connection timed out"); - break; - - case InProgress: - reason = i18n("Socket error code InProgress", - "operation is already in progress"); - break; - - case NetFailure: - reason = i18n("Socket error code NetFailure", - "network failure occurred"); - break; - - case NotSupported: - reason = i18n("Socket error code NotSupported", - "operation is not supported"); - break; - - case Timeout: - reason = i18n("Socket error code Timeout", - "timed operation timed out"); - break; - - case UnknownError: - reason = i18n("Socket error code UnknownError", - "an unknown/unexpected error has happened"); - break; - - case RemotelyDisconnected: - reason = i18n("Socket error code RemotelyDisconnected", - "remote host closed connection"); - break; - - default: - reason = TQString::null; - break; - } - - return reason; -} - -// static -bool KSocketBase::isFatalError(int code) -{ - switch (code) - { - case WouldBlock: - case InProgress: - case NoError: - case RemotelyDisconnected: - return false; - } - - return true; -} - -void KSocketBase::unsetSocketDevice() -{ - d->device = 0L; -} - -TQMutex* KSocketBase::mutex() const -{ - return &d->mutex; -} - -KActiveSocketBase::KActiveSocketBase() -{ -} - -KActiveSocketBase::~KActiveSocketBase() -{ -} - -int KActiveSocketBase::getch() -{ - unsigned char c; - if (tqreadBlock((char*)&c, 1) != 1) - return -1; - - return c; -} - -int KActiveSocketBase::putch(int ch) -{ - unsigned char c = (unsigned char)ch; - if (tqwriteBlock((char*)&c, 1) != 1) - return -1; - - return c; -} - -void KActiveSocketBase::setError(int status, SocketError error) -{ - KSocketBase::setError(error); - setStatus(status); -} - -void KActiveSocketBase::resetError() -{ - KSocketBase::setError(NoError); - resetStatus(); -} - -KPassiveSocketBase::KPassiveSocketBase() -{ -} - -KPassiveSocketBase::~KPassiveSocketBase() -{ -} diff --git a/tdecore/network/ksocketbase.h b/tdecore/network/ksocketbase.h deleted file mode 100644 index 48ae15e05..000000000 --- a/tdecore/network/ksocketbase.h +++ /dev/null @@ -1,771 +0,0 @@ -/* -*- 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 KSocketDevice; - -class KSocketBasePrivate; -/** @class KSocketBase 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 KSocketBase -{ -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. - */ - KSocketBase(); - - /** - * Destructor. - */ - virtual ~KSocketBase(); - - /* - * 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. - */ - KSocketDevice* 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(KSocketDevice* 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 KSocketDevice::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 KSocketDevice::capabilities, for instance) the availability. - * - * @param add mask of @ref KSocketDevice::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 KSocketDevice - void unsetSocketDevice(); - - KSocketBase(const KSocketBase&); - KSocketBase& operator =(const KSocketBase&); - - KSocketBasePrivate *d; - - friend class KSocketDevice; -}; - -/** - * @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 KSocketBase -{ -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, KSocketAddress& 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, KSocketAddress& 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 KSocketAddress& 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 KSocketAddress 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 KSocketAddress peerAddress() const = 0; - - // FIXME KDE 4.0: - // enable this function -#if 0 - /** - * Returns this socket's externally-visible address, if known. - */ - virtual KSocketAddress 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 KSocketBase -{ -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 KSocketAddress localAddress() const = 0; - - /** - * Returns this socket's externally-visible address if known. - */ - virtual KSocketAddress externalAddress() const = 0; - -private: - KPassiveSocketBase(const KPassiveSocketBase&); - KPassiveSocketBase& operator = (const KPassiveSocketBase&); -}; - -} // namespace KNetwork - -#endif diff --git a/tdecore/network/ksocketbuffer.cpp b/tdecore/network/ksocketbuffer.cpp deleted file mode 100644 index 0ba18b77b..000000000 --- a/tdecore/network/ksocketbuffer.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* -*- C++ -*- - * Copyright (C) 2003 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 -#include - -#include "tdesocketbase.h" -#include "tdesocketbuffer_p.h" - -using namespace KNetwork; -using namespace KNetwork::Internal; - -KSocketBuffer::KSocketBuffer(TQ_LONG size) - : m_mutex(true), m_offset(0), m_size(size), m_length(0) -{ -} - -KSocketBuffer::KSocketBuffer(const KSocketBuffer& other) - : KIOBufferBase(other), m_mutex(true) -{ - *this = other; -} - -KSocketBuffer::~KSocketBuffer() -{ - // TQValueList takes care of deallocating memory -} - -KSocketBuffer& KSocketBuffer::operator=(const KSocketBuffer& other) -{ - TQMutexLocker locker1(&m_mutex); - TQMutexLocker locker2(&other.m_mutex); - - KIOBufferBase::operator=(other); - - m_list = other.m_list; // copy-on-write - m_offset = other.m_offset; - m_size = other.m_size; - m_length = other.m_length; - - return *this; -} - -bool KSocketBuffer::canReadLine() const -{ - TQMutexLocker locker(&m_mutex); - - TQValueListConstIterator it = m_list.constBegin(), - end = m_list.constEnd(); - TQIODevice::Offset offset = m_offset; - - // walk the buffer - for ( ; it != end; ++it) - { - if ((*it).find('\n', offset) != -1) - return true; - if ((*it).find('\r', offset) != -1) - return true; - offset = 0; - } - - return false; // not found -} - -TQCString KSocketBuffer::readLine() -{ - if (!canReadLine()) - return TQCString(); // empty - - TQMutexLocker locker(&m_mutex); - - // find the offset of the newline in the buffer - int newline = 0; - TQValueListConstIterator it = m_list.constBegin(), - end = m_list.constEnd(); - TQIODevice::Offset offset = m_offset; - - // walk the buffer - for ( ; it != end; ++it) - { - int posnl = (*it).find('\n', offset); - if (posnl == -1) - { - // not found in this one - newline += (*it).size(); - offset = 0; - continue; - } - - // we found it - newline += posnl; - break; - } - - TQCString result(newline + 2 - m_offset); - consumeBuffer(result.data(), newline + 1 - m_offset); - return result; -} - -TQ_LONG KSocketBuffer::length() const -{ - return m_length; -} - -TQ_LONG KSocketBuffer::size() const -{ - return m_size; -} - -bool KSocketBuffer::setSize(TQ_LONG size) -{ - m_size = size; - if (size == -1 || m_length < m_size) - return true; - - // size is now smaller than length - TQMutexLocker locker(&m_mutex); - - // repeat the test - if (m_length < m_size) - return true; - - // discard from the beginning - return (m_length - m_size) == consumeBuffer(0L, m_length - m_size, true); -} - -TQ_LONG KSocketBuffer::feedBuffer(const char *data, TQ_LONG len) -{ - if (data == 0L || len == 0) - return 0; // nothing to write - if (isFull()) - return -1; // can't write - - TQMutexLocker locker(&m_mutex); - - // verify if we can add len bytes - if (m_size != -1 && (m_size - m_length) < len) - len = m_size - m_length; - - TQByteArray a(len); - a.duplicate(data, len); - m_list.append(a); - - m_length += len; - return len; -} - -TQ_LONG KSocketBuffer::consumeBuffer(char *destbuffer, TQ_LONG maxlen, bool discard) -{ - if (maxlen == 0 || isEmpty()) - return 0; - - TQValueListIterator it = m_list.begin(), - end = m_list.end(); - TQIODevice::Offset offset = m_offset; - TQ_LONG copied = 0; - - // walk the buffer - while (it != end && maxlen) - { - // calculate how much we'll copy - size_t to_copy = (*it).size() - offset; - if (to_copy > maxlen) - to_copy = maxlen; - - // do the copying - if (destbuffer) - memcpy(destbuffer + copied, (*it).data() + offset, to_copy); - maxlen -= to_copy; - copied += to_copy; - - if ((*it).size() - offset > to_copy) - { - // we did not copy everything - offset += to_copy; - break; - } - else - { - // we copied everything - // discard this element; - offset = 0; - if (discard) - it = m_list.remove(it); - else - ++it; - } - } - - if (discard) - { - m_offset = offset; - m_length -= copied; - assert(m_length >= 0); - } - - return copied; -} - -void KSocketBuffer::clear() -{ - TQMutexLocker locker(&m_mutex); - m_list.clear(); - m_offset = 0; - m_length = 0; -} - -TQ_LONG KSocketBuffer::sendTo(KActiveSocketBase* dev, TQ_LONG len) -{ - if (len == 0 || isEmpty()) - return 0; - - TQMutexLocker locker(&m_mutex); - - TQValueListIterator it = m_list.begin(), - end = m_list.end(); - TQIODevice::Offset offset = m_offset; - TQ_LONG written = 0; - - // walk the buffer - while (it != end && (len || len == -1)) - { - // we have to write each element up to len bytes - // but since we can have several very small buffers, we can make things - // better by concatenating a few of them into a big buffer - // question is: how big should that buffer be? 2 kB should be enough - - TQ_ULONG bufsize = 1460; - if (len != -1 && len < bufsize) - bufsize = len; - TQByteArray buf(bufsize); - TQ_LONG count = 0; - - while (it != end && count + ((*it).size() - offset) <= bufsize) - { - memcpy(buf.data() + count, (*it).data() + offset, (*it).size() - offset); - count += (*it).size() - offset; - offset = 0; - ++it; - } - - // see if we can still fit more - if (count < bufsize && it != end) - { - // getting here means this buffer (*it) is larger than - // (bufsize - count) (even for count == 0). - memcpy(buf.data() + count, (*it).data() + offset, bufsize - count); - offset += bufsize - count; - count = bufsize; - } - - // now try to write those bytes - TQ_LONG wrote = dev->tqwriteBlock(buf, count); - - if (wrote == -1) - // error? - break; - - written += wrote; - if (wrote != count) - // can't fit more? - break; - } - - // discard data that has been written - // this updates m_length too - if (written) - consumeBuffer(0L, written); - - return written; -} - -TQ_LONG KSocketBuffer::receiveFrom(KActiveSocketBase* dev, TQ_LONG len) -{ - if (len == 0 || isFull()) - return 0; - - TQMutexLocker locker(&m_mutex); - - if (len == -1) - len = dev->bytesAvailable(); - if (len <= 0) - // error or closing socket - return len; - - // see if we can read that much - if (m_size != -1 && len > (m_size - m_length)) - len = m_size - m_length; - - // here, len contains just as many bytes as we're supposed to read - - // now do the reading - TQByteArray a(len); - len = dev->tqreadBlock(a.data(), len); - - if (len == -1) - // error? - return -1; - - // success - // resize the buffer and add it - a.truncate(len); - m_list.append(a); - m_length += len; - return len; -} diff --git a/tdecore/network/ksocketbuffer_p.h b/tdecore/network/ksocketbuffer_p.h deleted file mode 100644 index b2c5dc6b2..000000000 --- a/tdecore/network/ksocketbuffer_p.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- C++ -*- - * Copyright (C) 2003 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. - */ - -#ifndef TDESOCKETBUFFER_P_H -#define TDESOCKETBUFFER_P_H - -#include -#include -#include -#include "kiobuffer.h" - -namespace KNetwork { - -class KActiveSocketBase; - - namespace Internal { - -/** - * @internal - * @class KSocketBuffer tdesocketbuffer_p.h tdesocketbuffer_p.h - * @brief generic socket buffering code - * - * This class implements generic buffering used by @ref KBufferedSocket. - * - * @author Thiago Macieira - */ -class KSocketBuffer: public KIOBufferBase -{ -public: - /** - * Default constructor. - * - * @param size the maximum size of the buffer - */ - KSocketBuffer(TQ_LONG size = -1); - - /** - * Copy constructor. - */ - KSocketBuffer(const KSocketBuffer& other); - - /** - * Virtual destructor. Frees the buffer and discards its contents. - */ - virtual ~KSocketBuffer(); - - /** - * Assignment operator. - */ - KSocketBuffer& operator=(const KSocketBuffer& other); - - /** - * Returns true if a line can be read from the buffer. - */ - virtual bool canReadLine() const; - - /** - * Reads a line from the buffer and discard it from the buffer. - */ - virtual TQCString readLine(); - - /** - * Returns the number of bytes in the buffer. Note that this is not - * the size of the buffer. - * - * @sa size - */ - virtual TQ_LONG length() const; - - /** - * Retrieves the buffer size. The value of -1 indicates that - * the buffer has no defined upper limit. - * - * @sa length for the length of the data stored - */ - virtual TQ_LONG size() const; - - /** - * Sets the size of the buffer, if allowed. - * - * @param size the maximum size, use -1 for unlimited. - * @returns true on success, false if an error occurred. - * @note if the new size is less than length(), the buffer will be truncated - */ - virtual bool setSize(TQ_LONG size); - - /** - * Adds data to the end of the buffer. - * - * @param data the data to be added - * @param len the data length, in bytes - * @returns the number of bytes added to the end of the buffer. - */ - virtual TQ_LONG feedBuffer(const char *data, TQ_LONG len); - - /** - * Clears the buffer. - */ - virtual void clear(); - - /** - * Consumes data from the beginning of the buffer. - * - * @param data where to copy the data to - * @param maxlen the maximum length to copy, in bytes - * @param discard if true, the bytes copied will be discarded - * @returns the number of bytes copied from the buffer - */ - virtual TQ_LONG consumeBuffer(char *data, TQ_LONG maxlen, bool discard = true); - - /** - * Sends at most @p len bytes of data to the I/O Device. - * - * @param device the device to which to send data - * @param len the amount of data to send; -1 to send everything - * @returns the number of bytes sent and discarded from the buffer, -1 - * indicates an error. - */ - virtual TQ_LONG sendTo(KActiveSocketBase* device, TQ_LONG len = -1); - - /** - * Tries to receive @p len bytes of data from the I/O device. - * - * @param device the device to receive from - * @param len the number of bytes to receive; -1 to read as much - * as possible - * @returns the number of bytes received and copied into the buffer, - * -1 indicates an error. - */ - virtual TQ_LONG receiveFrom(KActiveSocketBase* device, TQ_LONG len = -1); - -protected: - mutable TQMutex m_mutex; - TQValueList m_list; - TQIODevice::Offset m_offset; ///< offset of the start of data in the first element - - TQ_LONG m_size; ///< the maximum length of the buffer - mutable TQ_LONG m_length; -}; - -} } // namespace KNetwork::Internal - -#endif diff --git a/tdecore/network/ksocketdevice.cpp b/tdecore/network/ksocketdevice.cpp deleted file mode 100644 index 064b66b08..000000000 --- a/tdecore/network/ksocketdevice.cpp +++ /dev/null @@ -1,891 +0,0 @@ -/* -*- 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. - */ - -#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::KSocketDevicePrivate -{ -public: - mutable TQSocketNotifier *input, *output, *exception; - KSocketAddress local, peer; - int af; - - inline KSocketDevicePrivate() - { - input = output = exception = 0L; - af = 0; - } -}; - - -KSocketDevice::KSocketDevice(const KSocketBase* parent) - : m_sockfd(-1), d(new KSocketDevicePrivate) -{ - setSocketDevice(this); - if (parent) - setSocketOptions(parent->socketOptions()); -} - -KSocketDevice::KSocketDevice(int fd) - : m_sockfd(fd), d(new KSocketDevicePrivate) -{ - setState(IO_Open); - setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); - setSocketDevice(this); - d->af = localAddress().family(); -} - -KSocketDevice::KSocketDevice(bool, const KSocketBase* parent) - : m_sockfd(-1), d(new KSocketDevicePrivate) -{ - // do not set parent - if (parent) - setSocketOptions(parent->socketOptions()); -} - -KSocketDevice::~KSocketDevice() -{ - close(); // deletes the notifiers - unsetSocketDevice(); // prevent double deletion - delete d; -} - -bool KSocketDevice::setSocketOptions(int opts) -{ - // must call parent - TQMutexLocker locker(mutex()); - KSocketBase::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 KSocketDevice::open(TQ_OpenMode) -{ - resetError(); - return false; -} - -void KSocketDevice::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 KSocketDevice::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 KSocketDevice::create(const KResolverEntry& address) -{ - return create(address.family(), address.socketType(), address.protocol()); -} - -bool KSocketDevice::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 KSocketDevice::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 KSocketDevice::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 -} - -KSocketDevice* KSocketDevice::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 KSocketDevice(newfd); -} - -bool KSocketDevice::disconnect() -{ - resetError(); - - if (m_sockfd == -1) - return false; // can't create - - KSocketAddress 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 KSocketDevice::bytesAvailable() const -#endif -#ifdef USE_QT4 -qint64 KSocketDevice::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 KSocketDevice::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, KSocketAddress* 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 KSocketDevice::WouldBlock; - else - return KSocketDevice::UnknownError; - } - if (retval == 0) - return KSocketDevice::RemotelyDisconnected; - - if (from) - from->setLength(len); - return 0; -} - -TQT_TQIO_LONG KSocketDevice::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 KSocketDevice::tqreadBlock(char *data, TQT_TQIO_ULONG maxlen, KSocketAddress &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 KSocketDevice::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 KSocketDevice::peekBlock(char *data, TQ_ULONG maxlen, KSocketAddress& 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 KSocketDevice::tqwriteBlock(const char *data, TQT_TQIO_ULONG len) -{ - return tqwriteBlock(data, len, KSocketAddress()); -} - -TQT_TQIO_LONG KSocketDevice::tqwriteBlock(const char *data, TQT_TQIO_ULONG len, const KSocketAddress& 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; -} - -KSocketAddress KSocketDevice::localAddress() const -{ - if (m_sockfd == -1) - return KSocketAddress(); // not open, empty value - - if (d->local.family() != AF_UNSPEC) - return d->local; - - socklen_t len; - KSocketAddress localAddress; - localAddress.setLength(len = 32); // arbitrary value - if (kde_getsockname(m_sockfd, localAddress.address(), &len) == -1) - // error! - return d->local = KSocketAddress(); - -#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 = KSocketAddress(); - - return d->local = localAddress; -} - -KSocketAddress KSocketDevice::peerAddress() const -{ - if (m_sockfd == -1) - return KSocketAddress(); // not open, empty value - - if (d->peer.family() != AF_UNSPEC) - return d->peer; - - socklen_t len; - KSocketAddress peerAddress; - peerAddress.setLength(len = 32); // arbitrary value - if (kde_getpeername(m_sockfd, peerAddress.address(), &len) == -1) - // error! - return d->peer = KSocketAddress(); - -#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 = KSocketAddress(); - - return d->peer = peerAddress; -} - -KSocketAddress KSocketDevice::externalAddress() const -{ - // for normal sockets, the externally visible address is the same - // as the local address - return localAddress(); -} - -TQSocketNotifier* KSocketDevice::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* KSocketDevice::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* KSocketDevice::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 KSocketDevice::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 KSocketDevice::poll(int timeout, bool *timedout) -{ - bool input, output, exception; - return poll(&input, &output, &exception, timeout, timedout); -} - -TQSocketNotifier* KSocketDevice::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 KSocketDeviceFactoryBase* defaultImplFactory; -static TQMutex defaultImplFactoryMutex; -typedef TQMap factoryMap; -static factoryMap factories; - -KSocketDevice* KSocketDevice::createDefault(KSocketBase* parent) -{ - KSocketDevice* device = dynamic_cast(parent); - if (device != 0L) - return device; - - KSocksSocketDevice::initSocks(); - - if (defaultImplFactory) - return defaultImplFactory->create(parent); - - // the really default - return new KSocketDevice(parent); -} - -KSocketDevice* KSocketDevice::createDefault(KSocketBase* parent, int capabilities) -{ - KSocketDevice* 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 -} - -KSocketDeviceFactoryBase* -KSocketDevice::setDefaultImpl(KSocketDeviceFactoryBase* factory) -{ - TQMutexLocker locker(&defaultImplFactoryMutex); - KSocketDeviceFactoryBase* old = defaultImplFactory; - defaultImplFactory = factory; - return old; -} - -void KSocketDevice::addNewImpl(KSocketDeviceFactoryBase* factory, int capabilities) -{ - TQMutexLocker locker(&defaultImplFactoryMutex); - if (factories.contains(capabilities)) - delete factories[capabilities]; - factories.insert(capabilities, factory); -} - diff --git a/tdecore/network/ksocketdevice.h b/tdecore/network/ksocketdevice.h deleted file mode 100644 index 10856716d..000000000 --- a/tdecore/network/ksocketdevice.h +++ /dev/null @@ -1,433 +0,0 @@ -/* -*- C++ -*- - * Copyright (C) 2003 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. - */ - -#ifndef TDESOCKETDEVICE_H -#define TDESOCKETDEVICE_H - -#include -#include "tdesocketbase.h" - -namespace KNetwork { - -class KSocketDevice; -class KSocketDeviceFactoryBase; - -class KSocketDevicePrivate; -/** @class KSocketDevice tdesocketdevice.h tdesocketdevice.h - * @brief Low-level socket functionality. - * - * This class provides low-level socket functionality. - * - * Most users will prefer "cooked" interfaces like those of @ref KStreamSocket or - * @ref KServerSocket. - * - * Descended classes from this one provide some other kinds of socket functionality, - * like proxying or specific socket types. - * - * @author Thiago Macieira - */ -class TDECORE_EXPORT KSocketDevice: public KActiveSocketBase, public KPassiveSocketBase -{ -public: - /** - * Capabilities for the socket implementation. - * - * KSocketDevice-derived classes can implement certain capabilities that are not - * available in the default class. These capabilities are described by these flags. - * The default KSocketDevice class has none of these capabilities. - * - * For the negative capabilities (inabilities, the CanNot* forms), when a capability - * is not present, the implementation will default to the original behaviour. - */ - enum Capabilities - { - /** Can connect to hostnames. - * If this flag is present, the string form of @ref connect can be used. */ - CanConnectString = 0x01, - - /** Can bind to hostnames. - * If this flag is present, the string form of @ref bind can be used */ - CanBindString = 0x02, - - /** Can not bind. - * If this flag is present, this implementation cannot bind */ - CanNotBind = 0x04, - - /** Can not listen. - * If this flag is present, this implementation cannot listen */ - CanNotListen = 0x08, - - /** - * Can send multicast as well as join/leave multicast groups. - */ - CanMulticast = 0x10, - - /** - * Can not use datagrams. - * Note that this implies multicast capability not being available either. - */ - CanNotUseDatagrams = 0x20 - }; -protected: - /// The socket file descriptor. It is used throughout the implementation - /// and subclasses. - int m_sockfd; - -public: - /** - * Default constructor. - * - * The parameter is used to specify which socket this object is used as - * a device for. - */ - explicit KSocketDevice(const KSocketBase* = 0L); - - /** - * Constructs a new object around an already-open socket. - * - * Note: you should write programs that create sockets through - * the classes whenever possible. - */ - explicit KSocketDevice(int fd); - - /** - * Destructor. This closes the socket if it's open. - */ - virtual ~KSocketDevice(); - - /** - * Returns the file descriptor for this socket. - */ - inline int socket() const - { return m_sockfd; } - - /** - * Returns the set of capabilities this socket class implements. - * The set of capabilities is defined as an OR-ed mask of - * @ref Capabilities bits. - * - * The default implementation is guaranteed to always return 0. That - * is, derived implementations always return bits where they differ - * from the system standard sockets. - */ - virtual int capabilities() const - { return 0; } - - /** - * This implementation sets the options on the socket. - */ - virtual bool setSocketOptions(int opts); - - /** - * Reimplementation from TQIODevice. You should not call this function in sockets. - */ - virtual bool open(TQ_OpenMode mode); - - /** - * Closes the socket. Reimplemented from TQIODevice. - * - * Use this function to close the socket this object is holding open. - */ - virtual void close(); - - /** - * This call is not supported on sockets. Reimplemented from TQIODevice. - */ - virtual void flush() - { } - - /** - * Creates a socket but don't connect or bind anywhere. - * This function is the equivalent of the system call socket(2). - */ - virtual bool create(int family, int type, int protocol); - - /** - * @overload - * Creates a socket but don't connect or bind anywhere. - */ - bool create(const KResolverEntry& address); - - /** - * Binds this socket to the given address. - */ - virtual bool bind(const KResolverEntry& address); - - /** - * Puts this socket into listening mode. - */ - virtual bool listen(int backlog = 5); // 5 is arbitrary - - /** - * Connect to a remote host. - */ - virtual bool connect(const KResolverEntry& address); - - /** - * Accepts a new incoming connection. - * Note: this function returns a socket of type KSocketDevice. - */ - virtual KSocketDevice* accept(); - - /** - * Disconnects this socket. - */ - virtual bool disconnect(); - - /** - * Returns the number of bytes available for reading without blocking. - */ -#ifdef USE_QT3 - virtual TQ_LONG bytesAvailable() const; -#endif -#ifdef USE_QT4 - virtual qint64 bytesAvailable() const; -#endif - - /** - * Waits up to @p msecs for more data to be available on this socket. - * - * This function is a wrapper against @ref poll. This function will wait - * for any read events. - */ - virtual TQ_LONG waitForMore(int msecs, bool *timeout = 0L); - - /** - * Reads data from this socket. - */ - virtual TQT_TQIO_LONG tqreadBlock(char *data, TQT_TQIO_ULONG maxlen); - - /** - * Reads data and the source address from this socket. - */ - virtual TQT_TQIO_LONG tqreadBlock(char *data, TQT_TQIO_ULONG maxlen, KSocketAddress& from); - - /** - * Peeks data in the socket. - */ - virtual TQ_LONG peekBlock(char *data, TQ_ULONG maxlen); - - /** - * Peeks the data in the socket and the source address. - */ - virtual TQ_LONG peekBlock(char *data, TQ_ULONG maxlen, KSocketAddress& from); - - /** - * Writes data to the socket. - */ - virtual TQT_TQIO_LONG tqwriteBlock(const char *data, TQT_TQIO_ULONG len); - - /** - * Writes the given data to the given destination address. - */ - virtual TQT_TQIO_LONG tqwriteBlock(const char *data, TQT_TQIO_ULONG len, const KSocketAddress& to); - - /** - * Returns this socket's local address. - */ - virtual KSocketAddress localAddress() const; - - /** - * Returns this socket's peer address. If this implementation does proxying - * of some sort, this is the real external address, not the proxy's address. - */ - virtual KSocketAddress peerAddress() const; - - /** - * Returns this socket's externally visible local address. - * - * If this socket has a local address visible externally different - * from the normal local address (as returned by @ref localAddress), then - * return it. - * - * Certain implementations will use proxies and thus have externally visible - * addresses different from the local socket values. The default implementation - * returns the same value as @ref localAddress. - * - * @note This function may return an empty KSocketAddress. In that case, the - * externally visible address could/can not be determined. - */ - virtual KSocketAddress externalAddress() const; - - /** - * Returns a socket notifier for input on this socket. - * The notifier is created only when requested. Whether - * it is enabled or not depends on the implementation. - * - * This function might return NULL. - */ - TQSocketNotifier* readNotifier() const; - - /** - * Returns a socket notifier for output on this socket. - * The is created only when requested. - * - * This function might return NULL. - */ - TQSocketNotifier* writeNotifier() const; - - /** - * Returns a socket notifier for exceptional events on this socket. - * The is created only when requested. - * - * This function might return NULL. - */ - TQSocketNotifier* exceptionNotifier() const; - - /** - * Executes a poll in the socket, via select(2) or poll(2). - * The events polled are returned in the parameters pointers. - * Set any of them to NULL to disable polling of that event. - * - * On exit, @p input, @p output and @p exception will contain - * true if an event of that kind is waiting on the socket or false - * if not. If a timeout occurred, set @p timedout to true (all other - * parameters are necessarily set to false). - * - * @param input if set, turns on polling for input events - * @param output if set, turns on polling for output events - * @param exception if set, turns on polling for exceptional events - * @param timeout the time in milliseconds to wait for an event; - * 0 for no wait and any negative value to wait forever - * @param timedout on exit, will contain true if the polling timed out - * @return true if the poll call succeeded and false if an error occurred - */ - virtual bool poll(bool* input, bool* output, bool* exception = 0L, - int timeout = -1, bool* timedout = 0L); - - /** - * Shorter version to poll for any events in a socket. This call - * polls for input, output and exceptional events in a socket but - * does not return their states. This is useful if you need to wait for - * any event, but don't need to know which; or for timeouts. - * - * @param timeout the time in milliseconds to wait for an event; - * 0 for no wait and any negative value to wait forever - * @param timedout on exit, will contain true if the polling timed out - * @return true if the poll call succeeded and false if an error occurred - */ - bool poll(int timeout = -1, bool* timedout = 0L); - -protected: - /** - * Special constructor. This constructor will cause the internal - * socket device NOT to be set. Use this if your socket device class - * takes another underlying socket device. - * - * @param parent the parent, if any - */ - KSocketDevice(bool, const KSocketBase* parent = 0L); - - /** - * Creates a socket notifier of the given type. - * - * This function is called by @ref readNotifier, @ref writeNotifier and - * @ref exceptionNotifier when they need to create a socket notifier - * (i.e., the first call to those functions after the socket is open). - * After that call, those functions cache the socket notifier and will - * not need to call this function again. - * - * Reimplement this function in your derived class if your socket type - * requires a different kind of TQSocketNotifier. The return value should - * be deleteable with delete. (@ref close deletes them). - * - * @param type the socket notifier type - */ - virtual TQSocketNotifier* createNotifier(TQSocketNotifier::Type type) const; - -public: - /** - * Creates a new default KSocketDevice object given - * the parent object. - * - * The capabilities flag indicates the desired capabilities the object being - * created should possess. Those capabilities are not guaranteed: if no factory - * can provide such an object, a default object will be created. - * - * @param parent the KSocketBase parent - */ - static KSocketDevice* createDefault(KSocketBase* parent); - - /** - * @overload - * - * This will create an object only if the requested capabilities match. - * - * @param parent the parent - * @param capabilities the requested capabilities - */ - static KSocketDevice* createDefault(KSocketBase* parent, int capabilities); - - /** - * Sets the default KSocketDevice implementation to use and - * return the old factory. - * - * @param factory the factory object for the implementation - */ - static KSocketDeviceFactoryBase* setDefaultImpl(KSocketDeviceFactoryBase* factory); - - /** - * Adds a factory of KSocketDevice objects to the list, along with its - * capabilities flag. - */ - static void addNewImpl(KSocketDeviceFactoryBase* factory, int capabilities); - -private: - KSocketDevice(const KSocketDevice&); - KSocketDevice& operator=(const KSocketDevice&); - - KSocketDevicePrivate *d; -}; - -/** @internal - * This class provides functionality for creating and registering - * socket implementations. - */ -class KSocketDeviceFactoryBase -{ -public: - KSocketDeviceFactoryBase() {} - virtual ~KSocketDeviceFactoryBase() {} - - virtual KSocketDevice* create(KSocketBase*) const = 0; -}; - -/** - * This class provides functionality for creating and registering - * socket implementations. - */ -template -class KSocketDeviceFactory: public KSocketDeviceFactoryBase -{ -public: - KSocketDeviceFactory() {} - virtual ~KSocketDeviceFactory() {} - - virtual KSocketDevice* create(KSocketBase* parent) const - { return new Impl(parent); } -}; - -} // namespaces - -#endif diff --git a/tdecore/network/tdesocketaddress.cpp b/tdecore/network/tdesocketaddress.cpp new file mode 100644 index 000000000..d1234044b --- /dev/null +++ b/tdecore/network/tdesocketaddress.cpp @@ -0,0 +1,957 @@ +/* -*- C++ -*- + * Copyright (C) 2003 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 "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "klocale.h" +#include "tdesocketaddress.h" + +#include "netsupp.h" + +using namespace KNetwork; + +#if 0 +class KIpAddress_localhostV4 : public KIpAddress +{ +public: + KIpAddress_localhostV4() + { + *m_data = htonl(0x7f000001); + m_version = 4; + } +}; + +class KIpAddress_localhostV6 : public KIpAddress +{ +public: + KIpAddress_localhostV6() + : KIpAddress(0L, 6) + { + m_data[3] = htonl(1); + } +}; +#endif + +static const char localhostV4_data[] = { 127, 0, 0, 1 }; +static const char localhostV6_data[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,1 }; + +const KIpAddress KIpAddress::localhostV4(&localhostV4_data, 4); +const KIpAddress KIpAddress::localhostV6(&localhostV6_data, 6); +const KIpAddress KIpAddress::anyhostV4(0L, 4); +const KIpAddress KIpAddress::anyhostV6(0L, 6); + +// helper function to test if an IPv6 v4-mapped address is equal to its IPv4 counterpart +static bool check_v4mapped(const TQ_UINT32* v6addr, TQ_UINT32 v4addr) +{ + // check that the v6 is a v4-mapped address + if (!(v6addr[0] == 0 && v6addr[1] == 0 && v6addr[2] == htonl(0x0000ffff))) + return false; // not a v4-mapped address + + return v6addr[3] == v4addr; +} + +// copy operator +KIpAddress& KIpAddress::operator =(const KIpAddress& other) +{ + m_version = other.m_version; + if (m_version == 4 || m_version == 6) + memcpy(m_data, other.m_data, sizeof(m_data)); + return *this; +} + +// comparison +bool KIpAddress::compare(const KIpAddress& other, bool checkMapped) const +{ + if (m_version == other.m_version) + switch (m_version) + { + case 0: + // both objects are empty + return true; + + case 4: + // IPv4 address + return *m_data == *other.m_data; + + case 6: + // IPv6 address + // they are 128-bit long, that is, 16 bytes + return memcmp(m_data, other.m_data, 16) == 0; + } + + if (checkMapped) + { + // check the possibility of a v4-mapped address being compared to an IPv4 one + if (m_version == 6 && other.m_version == 4 && check_v4mapped(m_data, *other.m_data)) + return true; + + if (other.m_version == 6 && m_version == 4 && check_v4mapped(other.m_data, *m_data)) + return true; + } + + return false; +} + +// sets the address to the given address +bool KIpAddress::setAddress(const TQString& address) +{ + m_version = 0; + + // try to guess the address version + if (address.find(':') != -1) + { +#ifdef AF_INET6 + // guessing IPv6 + + TQ_UINT32 buf[4]; + if (inet_pton(AF_INET6, address.latin1(), buf)) + { + memcpy(m_data, buf, sizeof(m_data)); + m_version = 6; + return true; + } +#endif + + return false; + } + else + { + TQ_UINT32 buf; + if (inet_pton(AF_INET, address.latin1(), &buf)) + { + *m_data = buf; + m_version = 4; + return true; + } + + return false; + } + + return false; // can never happen! +} + +bool KIpAddress::setAddress(const char* address) +{ + return setAddress(TQString::fromLatin1(address)); +} + +// set from binary data +bool KIpAddress::setAddress(const void* raw, int version) +{ + // this always succeeds + // except if version is invalid + if (version != 4 && version != 6) + return false; + + m_version = version; + if (raw != 0L) + memcpy(m_data, raw, version == 4 ? 4 : 16); + else + memset(m_data, 0, 16); + + return true; +} + +// presentation form +TQString KIpAddress::toString() const +{ + char buf[sizeof "1111:2222:3333:4444:5555:6666:255.255.255.255" + 2]; + buf[0] = '\0'; + switch (m_version) + { + case 4: + inet_ntop(AF_INET, m_data, buf, sizeof(buf) - 1); + return TQString::fromLatin1(buf); + + case 6: +#ifdef AF_INET6 + inet_ntop(AF_INET6, m_data, buf, sizeof(buf) - 1); +#endif + return TQString::fromLatin1(buf); + } + + return TQString::null; +} + +TQ_UINT32 KIpAddress::hostIPv4Addr(bool convertMapped) const +{ + TQ_UINT32 addr = IPv4Addr(convertMapped); + return ntohl(addr); +} + +/* + * An IPv6 socket address + * This is taken from RFC 2553. + */ +struct our_sockaddr_in6 +{ +# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + TQ_UINT8 sin6_len; + TQ_UINT8 sin6_family; +# else //!HAVE_STRUCT_SOCKADDR_SA_LEN + TQ_UINT16 sin6_family; +# endif + TQ_UINT16 sin6_port; /* RFC says in_port_t */ + TQ_UINT32 sin6_flowinfo; + TQ_UINT8 sin6_addr[16]; // 24 bytes up to here + TQ_UINT32 sin6_scope_id; // 28 bytes total +}; + +// useful definitions +#define MIN_SOCKADDR_LEN sizeof(TQ_UINT16) +#define SOCKADDR_IN_LEN sizeof(sockaddr_in) +#define MIN_SOCKADDR_IN6_LEN ((unsigned long) &(((our_sockaddr_in6*)0)->sin6_scope_id)) +#define SOCKADDR_IN6_LEN sizeof(our_sockaddr_in6) +#define MIN_SOCKADDR_UN_LEN (sizeof(TQ_UINT16) + sizeof(char)) + + +class KNetwork::KSocketAddressData +{ +public: + /* + * Note: maybe this should be virtual + * But since the data is shared via the d pointer, it doesn't really matter + * what one class sees, so will the other + */ + class QMixSocketAddressRef : public KInetSocketAddress, public KUnixSocketAddress + { + public: + QMixSocketAddressRef(KSocketAddressData* d) + : KInetSocketAddress(d), KUnixSocketAddress(d) + { + } + }; + QMixSocketAddressRef ref; + + union + { + struct sockaddr *generic; + struct sockaddr_in *in; + struct our_sockaddr_in6 *in6; + struct sockaddr_un *un; + } addr; + TQ_UINT16 curlen, reallen; + + KSocketAddressData() + : ref(this) + { + addr.generic = 0L; + curlen = 0; + invalidate(); + } + + ~KSocketAddressData() + { + if (addr.generic != 0L) + free(addr.generic); + } + + inline bool invalid() const + { return reallen == 0; } + + inline void invalidate() + { reallen = 0; } + + void dup(const sockaddr* sa, TQ_UINT16 len, bool clear = true); + + void makeipv4() + { + short oldport = 0; + if (!invalid()) + switch (addr.generic->sa_family) + { + case AF_INET: + return; // nothing to do here +#ifdef AF_INET6 + case AF_INET6: + oldport = addr.in6->sin6_port; + break; +#endif + } + + // create new space + dup(0L, SOCKADDR_IN_LEN); + + addr.in->sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + addr.in->sin_len = SOCKADDR_IN_LEN; +#endif + addr.in->sin_port = oldport; + } + + void makeipv6() + { + short oldport = 0; + if (!invalid()) + switch (addr.generic->sa_family) + { + case AF_INET: + oldport = addr.in->sin_port; + break; + +#ifdef AF_INET6 + case AF_INET6: + return; // nothing to do here +#endif + } + + // make room + dup(0L, SOCKADDR_IN6_LEN); +#ifdef AF_INET6 + addr.in6->sin6_family = AF_INET6; +#endif +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + addr.in6->sin6_len = SOCKADDR_IN6_LEN; +#endif + addr.in6->sin6_port = oldport; + // sin6_scope_id and sin6_flowid are zero + } + +}; + +// create duplicates of +void KSocketAddressData::dup(const sockaddr* sa, TQ_UINT16 len, bool clear) +{ + if (len < MIN_SOCKADDR_LEN) + { + // certainly invalid + invalidate(); + return; + } + + if (sa && ((sa->sa_family == AF_INET && len < SOCKADDR_IN_LEN) || +#ifdef AF_INET6 + (sa->sa_family == AF_INET6 && len < MIN_SOCKADDR_IN6_LEN) || +#endif + (sa->sa_family == AF_UNIX && len < MIN_SOCKADDR_UN_LEN))) + { + // also invalid + invalidate(); + return; + } + + // good + reallen = len; + if (len > curlen) + { + if (len < 32) + curlen = 32; // big enough for sockaddr_in and sockaddr_in6 + else + curlen = len; + addr.generic = (sockaddr*)realloc(addr.generic, curlen); + } + + if (sa != 0L) + { + memcpy(addr.generic, sa, len); // copy + + // now, normalise the data + if (addr.generic->sa_family == AF_INET) + reallen = SOCKADDR_IN_LEN; // no need to be larger +#ifdef AF_INET6 + else if (addr.generic->sa_family == AF_INET6) + { + // set the extra field (sin6_scope_id) + + // the buffer is never smaller than 32 bytes, so this is always + // allowed + if (reallen < SOCKADDR_IN6_LEN) + addr.in6->sin6_scope_id = 0; + + reallen = SOCKADDR_IN6_LEN; + } +#endif + else if (addr.generic->sa_family == AF_UNIX) + reallen = MIN_SOCKADDR_UN_LEN + strlen(addr.un->sun_path); + } + else if (clear) + { + memset(addr.generic, 0, len); + addr.generic->sa_family = AF_UNSPEC; + } +} + +// default constructor +KSocketAddress::KSocketAddress() + : d(new KSocketAddressData) +{ +} + +// constructor from binary data +KSocketAddress::KSocketAddress(const sockaddr *sa, TQ_UINT16 len) + : d(new KSocketAddressData) +{ + setAddress(sa, len); +} + +KSocketAddress::KSocketAddress(const KSocketAddress& other) + : d(new(KSocketAddressData)) +{ + *this = other; +} + +KSocketAddress::KSocketAddress(KSocketAddressData *d2) + : d(d2) +{ +} + +KSocketAddress::~KSocketAddress() +{ + // prevent double-deletion, since we're already being deleted + if (d) + { + d->ref.KInetSocketAddress::d = 0L; + d->ref.KUnixSocketAddress::d = 0L; + delete d; + } +} + +KSocketAddress& KSocketAddress::operator =(const KSocketAddress& other) +{ + if (other.d && !other.d->invalid()) + d->dup(other.d->addr.generic, other.d->reallen); + else + d->invalidate(); + return *this; +} + +const sockaddr* KSocketAddress::address() const +{ + if (d->invalid()) + return 0L; + return d->addr.generic; +} + +sockaddr* KSocketAddress::address() +{ + if (d->invalid()) + return 0L; + return d->addr.generic; +} + +KSocketAddress& KSocketAddress::setAddress(const sockaddr* sa, TQ_UINT16 len) +{ + if (sa != 0L && len >= MIN_SOCKADDR_LEN) + d->dup(sa, len); + else + d->invalidate(); + + return *this; +} + +TQ_UINT16 KSocketAddress::length() const +{ + if (d->invalid()) + return 0; + return d->reallen; +} + +KSocketAddress& KSocketAddress::setLength(TQ_UINT16 len) +{ + d->dup((sockaddr*)0L, len, false); + + return *this; +} + +int KSocketAddress::family() const +{ + if (d->invalid()) + return AF_UNSPEC; + return d->addr.generic->sa_family; +} + +KSocketAddress& KSocketAddress::setFamily(int family) +{ + if (d->invalid()) + d->dup((sockaddr*)0L, MIN_SOCKADDR_LEN); + d->addr.generic->sa_family = family; + + return *this; +} + +bool KSocketAddress::operator ==(const KSocketAddress& other) const +{ + // if this is invalid, it's only equal if the other one is invalid as well + if (d->invalid()) + return other.d->invalid(); + + // check the family to make sure we don't do unnecessary comparison + if (d->addr.generic->sa_family != other.d->addr.generic->sa_family) + return false; // not the same family, not equal + + // same family then + // check the ones we know already + switch (d->addr.generic->sa_family) + { + case AF_INET: + Q_ASSERT(d->reallen == SOCKADDR_IN_LEN); + Q_ASSERT(other.d->reallen == SOCKADDR_IN_LEN); + return memcmp(d->addr.in, other.d->addr.in, SOCKADDR_IN_LEN) == 0; + +#ifdef AF_INET6 + case AF_INET6: + Q_ASSERT(d->reallen >= MIN_SOCKADDR_IN6_LEN); + Q_ASSERT(other.d->reallen >= MIN_SOCKADDR_IN6_LEN); + +# if !defined(HAVE_STRUCT_SOCKADDR_IN6) || defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID) + // check for the case where sin6_scope_id isn't present + if (d->reallen != other.d->reallen) + { + if (memcmp(d->addr.in6, other.d->addr.in6, MIN_SOCKADDR_IN6_LEN) != 0) + return false; // not equal + if (d->reallen > other.d->reallen) + return d->addr.in6->sin6_scope_id == 0; + else + return other.d->addr.in6->sin6_scope_id == 0; + } +# endif + + return memcmp(d->addr.in6, other.d->addr.in6, d->reallen) == 0; +#endif + + case AF_UNIX: + Q_ASSERT(d->reallen >= MIN_SOCKADDR_UN_LEN); + Q_ASSERT(other.d->reallen >= MIN_SOCKADDR_UN_LEN); + + // do a string comparison here + return strcmp(d->addr.un->sun_path, other.d->addr.un->sun_path) == 0; + + default: + // something else we don't know about + // they are equal if and only if they are exactly equal + if (d->reallen == other.d->reallen) + return memcmp(d->addr.generic, other.d->addr.generic, d->reallen) == 0; + } + + return false; // not equal in any other case +} + +TQString KSocketAddress::nodeName() const +{ + if (d->invalid()) + return TQString::null; + + switch (d->addr.generic->sa_family) + { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: + + TQString scopeid("%"); + if (d->addr.generic->sa_family == AF_INET6 && d->addr.in6->sin6_scope_id) + scopeid += TQString::number(d->addr.in6->sin6_scope_id); + else + scopeid.truncate(0); + return d->ref.ipAddress().toString() + scopeid; +#else + return d->ref.ipAddress().toString(); +#endif + } + + // any other case, including AF_UNIX + return TQString::null; +} + +TQString KSocketAddress::serviceName() const +{ + if (d->invalid()) + return TQString::null; + + switch (d->addr.generic->sa_family) + { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + return TQString::number(d->ref.port()); + + case AF_UNIX: + return d->ref.pathname(); + } + + return TQString::null; +} + +TQString KSocketAddress::toString() const +{ + if (d->invalid()) + return TQString::null; + + TQString fmt; + + if (d->addr.generic->sa_family == AF_INET) + fmt = "%1:%2"; +#ifdef AF_INET6 + else if (d->addr.generic->sa_family == AF_INET6) + fmt = "[%1]:%2"; +#endif + else if (d->addr.generic->sa_family == AF_UNIX) + return TQString::fromLatin1("unix:%1").arg(serviceName()); + else + return i18n("1: the unknown socket address family number", + "Unknown family %1").arg(d->addr.generic->sa_family); + + return fmt.arg(nodeName()).arg(serviceName()); +} + +KInetSocketAddress& KSocketAddress::asInet() +{ + return d->ref; +} + +KInetSocketAddress KSocketAddress::asInet() const +{ + return d->ref; +} + +KUnixSocketAddress& KSocketAddress::asUnix() +{ + return d->ref; +} + +KUnixSocketAddress KSocketAddress::asUnix() const +{ + return d->ref; +} + +int KSocketAddress::ianaFamily(int af) +{ + switch (af) + { + case AF_INET: + return 1; + +#ifdef AF_INET6 + case AF_INET6: + return 2; +#endif + + default: + return 0; + } +} + +int KSocketAddress::fromIanaFamily(int iana) +{ + switch (iana) + { + case 1: + return AF_INET; + +#ifdef AF_INET6 + case 2: + return AF_INET6; +#endif + + default: + return AF_UNSPEC; + } +} + +// default constructor +KInetSocketAddress::KInetSocketAddress() +{ +} + +// binary data constructor +KInetSocketAddress::KInetSocketAddress(const sockaddr* sa, TQ_UINT16 len) + : KSocketAddress(sa, len) +{ + if (!d->invalid()) + update(); +} + +// create from IP and port +KInetSocketAddress::KInetSocketAddress(const KIpAddress& host, TQ_UINT16 port) +{ + setHost(host); + setPort(port); +} + +// copy constructor +KInetSocketAddress::KInetSocketAddress(const KInetSocketAddress& other) + : KSocketAddress(other) +{ +} + +// special copy constructor +KInetSocketAddress::KInetSocketAddress(const KSocketAddress& other) + : KSocketAddress(other) +{ + if (!d->invalid()) + update(); +} + +// special constructor +KInetSocketAddress::KInetSocketAddress(KSocketAddressData *d) + : KSocketAddress(d) +{ +} + +// destructor +KInetSocketAddress::~KInetSocketAddress() +{ + /* nothing to do */ +} + +// copy operator +KInetSocketAddress& KInetSocketAddress::operator =(const KInetSocketAddress& other) +{ + KSocketAddress::operator =(other); + return *this; +} + +// IP version +int KInetSocketAddress::ipVersion() const +{ + if (d->invalid()) + return 0; + + switch (d->addr.generic->sa_family) + { + case AF_INET: + return 4; + +#ifdef AF_INET6 + case AF_INET6: + return 6; +#endif + } + + return 0; // for all other cases +} + +KIpAddress KInetSocketAddress::ipAddress() const +{ + if (d->invalid()) + return KIpAddress(); // return an empty address as well + + switch (d->addr.generic->sa_family) + { + case AF_INET: + return KIpAddress(&d->addr.in->sin_addr, 4); +#ifdef AF_INET6 + case AF_INET6: + return KIpAddress(&d->addr.in6->sin6_addr, 6); +#endif + } + + return KIpAddress(); // empty in all other cases +} + +KInetSocketAddress& KInetSocketAddress::setHost(const KIpAddress& ip) +{ + switch (ip.version()) + { + case 4: + makeIPv4(); + memcpy(&d->addr.in->sin_addr, ip.addr(), sizeof(d->addr.in->sin_addr)); + break; + + case 6: + makeIPv6(); + memcpy(&d->addr.in6->sin6_addr, ip.addr(), sizeof(d->addr.in6->sin6_addr)); + break; + + default: + // empty + d->invalidate(); + } + + return *this; +} + +// returns the port +TQ_UINT16 KInetSocketAddress::port() const +{ + if (d->invalid()) + return 0; + + switch (d->addr.generic->sa_family) + { + case AF_INET: + return ntohs(d->addr.in->sin_port); + +#ifdef AF_INET6 + case AF_INET6: + return ntohs(d->addr.in6->sin6_port); +#endif + } + + return 0; +} + +KInetSocketAddress& KInetSocketAddress::setPort(TQ_UINT16 port) +{ + if (d->invalid()) + makeIPv4(); + + switch (d->addr.generic->sa_family) + { + case AF_INET: + d->addr.in->sin_port = htons(port); + break; + +#ifdef AF_INET6 + case AF_INET6: + d->addr.in6->sin6_port = htons(port); + break; +#endif + + default: + d->invalidate(); // setting the port on something else + } + + return *this; +} + +KInetSocketAddress& KInetSocketAddress::makeIPv4() +{ + d->makeipv4(); + return *this; +} + +KInetSocketAddress& KInetSocketAddress::makeIPv6() +{ + d->makeipv6(); + return *this; +} + +TQ_UINT32 KInetSocketAddress::flowinfo() const +{ +#ifndef AF_INET6 + return 0; +#else + + if (!d->invalid() && d->addr.in6->sin6_family == AF_INET6) + return d->addr.in6->sin6_flowinfo; + return 0; +#endif +} + +KInetSocketAddress& KInetSocketAddress::setFlowinfo(TQ_UINT32 flowinfo) +{ + makeIPv6(); // must set here + d->addr.in6->sin6_flowinfo = flowinfo; + return *this; +} + +int KInetSocketAddress::scopeId() const +{ +#ifndef AF_INET6 + return 0; +#else + + if (!d->invalid() && d->addr.in6->sin6_family == AF_INET6) + return d->addr.in6->sin6_scope_id; + return 0; +#endif +} + +KInetSocketAddress& KInetSocketAddress::setScopeId(int scopeid) +{ + makeIPv6(); // must set here + d->addr.in6->sin6_scope_id = scopeid; + return *this; +} + +void KInetSocketAddress::update() +{ + if (d->addr.generic->sa_family == AF_INET) + return; +#ifdef AF_INET6 + else if (d->addr.generic->sa_family == AF_INET6) + return; +#endif + else + d->invalidate(); +} + +KUnixSocketAddress::KUnixSocketAddress() +{ +} + +KUnixSocketAddress::KUnixSocketAddress(const sockaddr* sa, TQ_UINT16 len) + : KSocketAddress(sa, len) +{ + if (!d->invalid() && d->addr.un->sun_family != AF_UNIX) + d->invalidate(); +} + +KUnixSocketAddress::KUnixSocketAddress(const KUnixSocketAddress& other) + : KSocketAddress(other) +{ +} + +KUnixSocketAddress::KUnixSocketAddress(const TQString& pathname) +{ + setPathname(pathname); +} + +KUnixSocketAddress::KUnixSocketAddress(KSocketAddressData* d) + : KSocketAddress(d) +{ +} + +KUnixSocketAddress::~KUnixSocketAddress() +{ +} + +KUnixSocketAddress& KUnixSocketAddress::operator =(const KUnixSocketAddress& other) +{ + KSocketAddress::operator =(other); + return *this; +} + +TQString KUnixSocketAddress::pathname() const +{ + if (!d->invalid() && d->addr.un->sun_family == AF_UNIX) + return TQFile::decodeName(d->addr.un->sun_path); + return TQString::null; +} + +KUnixSocketAddress& KUnixSocketAddress::setPathname(const TQString& path) +{ + d->dup(0L, MIN_SOCKADDR_UN_LEN + path.length()); + d->addr.un->sun_family = AF_UNIX; + strcpy(d->addr.un->sun_path, TQFile::encodeName(path)); + +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + d->addr.un->sun_len = d->reallen; +#endif + + return *this; +} diff --git a/tdecore/network/tdesocketaddress.h b/tdecore/network/tdesocketaddress.h new file mode 100644 index 000000000..885bb77cb --- /dev/null +++ b/tdecore/network/tdesocketaddress.h @@ -0,0 +1,912 @@ +/* -*- C++ -*- + * Copyright (C) 2003 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. + */ + +#ifndef TDESOCKETADDRESS_H +#define TDESOCKETADDRESS_H + +#include +#include + +#include + +struct sockaddr; +struct sockaddr_in; +struct sockaddr_in6; +struct sockaddr_un; + +namespace KNetwork { + +class KIpAddress; +class KSocketAddress; +class KInetSocketAddress; +class KUnixSocketAddress; + +/** @class KIpAddress tdesocketaddress.h tdesocketaddress.h + * @brief An IP address. + * + * This class represents one IP address, version 4 or 6. This is only + * the address, not including port information or other data. + * + * It is not a good programming practice to create address from objects + * like this. Instead, prefer a more thorough function like + * @ref KResolver::resolve, which also handle extra information like scope + * ids. + * + * This is a light-weight class. Most of the member functions are inlined and + * there are no virtual functions. This object's size should be less than 20 + * bytes. Also note that there is no sharing of data. + * + * @author Thiago Macieira + */ +class TDECORE_EXPORT KIpAddress +{ +public: + /** + * Default constructor. Creates an empty address. + * It defaults to IP version 4. + */ + inline KIpAddress() : m_version(0) + { } + + /** + * Copy constructor. Copies the data from the other + * object. + * + * Data is not shared. + * + * @param other the other + */ + inline KIpAddress(const KIpAddress& other) + { *this = other; } + + /** + * Creates an object from the given string representation. + * + * The IP version is guessed from the address format. + * + * @param addr the address + */ + inline KIpAddress(const TQString& addr) + { setAddress(addr); } + + /** + * Creates an object from the given string representation. + * + * The IP version is guessed from the address format. + * + * @param addr the address + */ + inline KIpAddress(const char* addr) + { setAddress(addr); } + + /** + * Creates an object from the given raw data and IP version. + * + * @param addr the raw data + * @param version the IP version (4 or 6) + */ + inline KIpAddress(const void* addr, int version = 4) + { setAddress(addr, version); } + + /** + * This is a convenience constructor. Constructs an object + * from the given IPv4 address in the form of an integer. + * + * Note: do not write code to depend on IPv4 addresses being + * integer types. Instead, treat them as a special type, like + * a KIpAddress or the system's in_addr. + * + * @param ip4addr the IPv4 address + */ + inline KIpAddress(TQ_UINT32 ip4addr) + { setAddress(&ip4addr, 4); } + + /** + * Destructor. This frees resources associated with this object. + * + * Note: destructor is non-virtual. The compiler will happily optimise it + * out of the way. + */ + inline ~KIpAddress() + { } + + /** + * Copy operator. + * + * Copies the data from the other object into this one. + * + * @param other the object to copy + */ + KIpAddress& operator =(const KIpAddress& other); + + /** + * Returns true if the two addresses match. + * This function performs a v4-mapped check. + * @see compare + */ + inline bool operator ==(const KIpAddress& other) const + { return compare(other, true); } + + /** + * Compares this address against the other, supplied one and return + * true if they match. The @p checkMapped parameter controls whether + * a check for an IPv6 v4-mapped address will be performed. + * + * An IPv6 v4-mapped address is an IPv6 address that is, for all purposes, + * equivalent to an IPv4 one. The default behaviour of this function + * is to take that into account. If you want a strict matching, + * pass @b false to the @p checkMapped parameter. + * + * @param other the other IP address + * @param checkMapped whether v4-mapped addresses will be taken into account + */ + bool compare(const KIpAddress& other, bool checkMapped = true) const; + + /** + * Retrieves the IP version in this object. + * + * @returns the version: 4 or 6 + */ + inline int version() const + { return m_version; } + + /** + * Returns true if this is an IPv4 address. + */ + inline bool isIPv4Addr() const + { return version() == 4; } + + /** + * Returns true if this is an IPv6 address. + */ + inline bool isIPv6Addr() const + { return version() == 6; } + + /** + * Sets the address to the given string representation. + * + * @return true if the address was successfully parsed; otherwise returns + * false and leaves the object unchanged. + */ + bool setAddress(const TQString& address); + + /** + * Sets the address to the given string representation. + * + * @return true if the address was successfully parsed; otherwise returns + * false and leaves the object unchanged. + */ + bool setAddress(const char* address); + + /** + * Sets the address to the given raw binary representation. + * + * @param raw a pointer to the raw binary data + * @param version the IP version + * @return true if the address was successfully parsed; otherwise returns + * false and leaves the object unchanged. + */ + bool setAddress(const void* raw, int version = 4); + + /** + * Returns the address as a string. + */ + TQString toString() const; + + /** + * Returns a pointer to binary raw data representing the address. + */ + inline const void *addr() const + { return m_data; } + + /** + * This is a convenience function. Returns the IPv4 address in a + * 32-bit integer. The result is only valid if @ref isIPv4Addr returns + * true. Alternatively, if the contained IPv6 address is a v4-mapped one + * and the @p convertMapped parameter is true, the result will also be + * valid. The address returned is in network byte order. + * + * Note: you should not treat IP addresses as integers. Instead, + * use types defined for that purpose, such as KIpAddress or the + * system's in_addr type. + * + */ + inline TQ_UINT32 IPv4Addr(bool convertMapped = true) const + { + return (convertMapped && isV4Mapped()) ? m_data[3] : m_data[0]; + } + + /** + * This is a convenience function. Returns the IPv4 address in a + * 32-bit integer. The result is only valid if @ref isIPv4Addr returns + * true. Alternatively, if the contained IPv6 address is a v4-mapped one + * and the @p convertMapped parameter is true, the result will also be + * valid. The address returned is in host byte order. + * + */ + TQ_UINT32 hostIPv4Addr(bool convertMapped = true) const; + +public: + /*-- tests --*/ + + /** + * Returns true if this is the IPv4 or IPv6 unspecified address. + */ + inline bool isUnspecified() const + { return version() == 0 ? true : (*this == anyhostV4 || *this == anyhostV6); } + + /** + * Returns true if this is either the IPv4 or the IPv6 localhost address. + */ + inline bool isLocalhost() const + { return version() == 0 ? false : (*this == localhostV4 || *this == localhostV6); } + + /** + * This is an alias for @ref isLocalhost. + */ + inline bool isLoopback() const + { return isLocalhost(); } + + /** + * Returns true if this is an IPv4 class A address, i.e., + * from 0.0.0.0 to 127.255.255.255. + * + * This function does not test for v4-mapped addresses. + */ + inline bool isClassA() const + { return version() != 4 ? false : (hostIPv4Addr() & 0x80000000) == 0; } + + /** + * Returns true if this is an IPv4 class B address, i.e., one from + * 128.0.0.0 to 191.255.255.255. + * + * This function does not test for v4-mapped addresses. + */ + inline bool isClassB() const + { return version() != 4 ? false : (hostIPv4Addr() & 0xc0000000) == 0x80000000; } + + /** + * Returns true if this is an IPv4 class C address, i.e., one from + * 192.0.0.0 to 223.255.255.255. + * + * This function does not test for v4-mapped addresses. + */ + inline bool isClassC() const + { return version() != 4 ? false : (hostIPv4Addr() & 0xe0000000) == 0xc0000000; } + + /** + * Returns true if this is an IPv4 class D (a.k.a. multicast) address. + * + * Note: this function is not the same as @ref isMulticast. isMulticast also + * tests for IPv6 multicast addresses. + */ + inline bool isClassD() const + { return version() != 4 ? false : (hostIPv4Addr() & 0xf0000000) == 0xe0000000; } + + /** + * Returns true if this is a multicast address, be it IPv4 or IPv6. + */ + inline bool isMulticast() const + { + if (version() == 4) return isClassD(); + if (version() == 6) return ((TQ_UINT8*)addr())[0] == 0xff; + return false; + } + + /** + * Returns true if this is an IPv6 link-local address. + */ + inline bool isLinkLocal() const + { + if (version() != 6) return false; + TQ_UINT8* addr = (TQ_UINT8*)this->addr(); + return (addr[0] & 0xff) == 0xfe && + (addr[1] & 0xc0) == 0x80; + } + + /** + * Returns true if this is an IPv6 site-local address. + */ + inline bool isSiteLocal() const + { + if (version() != 6) return false; + TQ_UINT8* addr = (TQ_UINT8*)this->addr(); + return (addr[0] & 0xff) == 0xfe && + (addr[1] & 0xc0) == 0xc0; + } + + /** + * Returns true if this is a global IPv6 address. + */ + inline bool isGlobal() const + { return version() != 6 ? false : !(isMulticast() || isLinkLocal() || isSiteLocal()); } + + /** + * Returns true if this is a v4-mapped IPv6 address. + */ + inline bool isV4Mapped() const + { + if (version() != 6) return false; + TQ_UINT32* addr = (TQ_UINT32*)this->addr(); + return addr[0] == 0 && addr[1] == 0 && + ((TQ_UINT16*)&addr[2])[0] == 0 && + ((TQ_UINT16*)&addr[2])[1] == 0xffff; + } + + /** + * Returns true if this is a v4-compat IPv6 address. + */ + inline bool isV4Compat() const + { + if (version() != 6 || isLocalhost()) return false; + TQ_UINT32* addr = (TQ_UINT32*)this->addr(); + return addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] != 0; + } + + /** + * Returns true if this is an IPv6 node-local multicast address. + */ + inline bool isMulticastNodeLocal() const + { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0x1; } + + /** + * Returns true if this is an IPv6 link-local multicast address. + */ + inline bool isMulticastLinkLocal() const + { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0x2; } + + /** + * Returns true if this is an IPv6 site-local multicast address. + */ + inline bool isMulticastSiteLocal() const + { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0x5; } + + /** + * Returns true if this is an IPv6 organisational-local multicast address. + */ + inline bool isMulticastOrgLocal() const + { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0x8; } + + /** + * Returns true if this is an IPv6 global multicast address. + */ + inline bool isMulticastGlobal() const + { return version() == 6 && isMulticast() && (((TQ_UINT32*)addr())[0] & 0xf) == 0xe; } + +protected: + TQ_UINT32 m_data[4]; // 16 bytes, needed for an IPv6 address + + char m_version; + +public: + /// localhost in IPv4 (127.0.0.1) + static const KIpAddress localhostV4; + /// the any host or undefined address in IPv4 (0.0.0.0) + static const KIpAddress anyhostV4; + + /// localhost in IPv6 (::1) + static const KIpAddress localhostV6; + /// the any host or undefined address in IPv6 (::) + static const KIpAddress anyhostV6; +}; + + +class KSocketAddressData; +/** @class KSocketAddress tdesocketaddress.h tdesocketaddress.h + * @brief A generic socket address. + * + * This class holds one generic socket address. + * + * @author Thiago Macieira + */ +class TDECORE_EXPORT KSocketAddress +{ +public: + /** + * Default constructor. + * + * Creates an empty object + */ + KSocketAddress(); + + /** + * Creates this object with the given data. + * The raw socket address is copied into this object. + * + * @param sa the socket address structure + * @param len the socket address length + */ + KSocketAddress(const sockaddr* sa, TQ_UINT16 len); + + /** + * Copy constructor. This creates a copy of the other + * object. + * + * Data is not shared. + * + * @param other the object to copy from + */ + KSocketAddress(const KSocketAddress& other); + + /** + * Destructor. Frees any associated resources. + */ + virtual ~KSocketAddress(); + + /** + * Performs a shallow copy of the other object into this one. + * Data will be copied. + * + * @param other the object to copy from + */ + KSocketAddress& operator =(const KSocketAddress& other); + + /** + * Returns the socket address structure, to be passed down to + * low level functions. + * + * Note that this function returns NULL for invalid or empty sockets, + * so you may use to to test for validity. + */ + const sockaddr* address() const; + + /** + * Returns the socket address structure, to be passed down to + * low level functions. + * + * Note that this function returns NULL for invalid or empty sockets, + * so you may use to to test for validity. + * + * The returned value, if not NULL, is an internal buffer which is guaranteed + * to be at least @ref length() bytes long. + */ + sockaddr* address(); + + /** + * Sets the address to the given address. + * The raw socket address is copied into this object. + * + * @param sa the socket address structure + * @param len the socket address length + */ + KSocketAddress& setAddress(const sockaddr *sa, TQ_UINT16 len); + + /** + * Returns the socket address structure, to be passed down to + * low level functions. + */ + inline operator const sockaddr*() const + { return address(); } + + /** + * Returns the length of this socket address structure. + */ + TQ_UINT16 length() const; + + /** + * Sets the length of this socket structure. + * + * Use this function with care. It allows you to resize the internal + * buffer to fit needs. This function should not be used except for handling + * unknown socket address structures. + * + * Also note that this function may invalidate the socket if a known + * family is set (Internet or Unix socket) and the new length would be + * too small to hold the system's sockaddr_* structure. If unsure, reset + * the family: + * + * \code + * KSocketAddress qsa; + * [...] + * qsa.setFamily(AF_UNSPEC).setLength(newlen); + * \endcode + * + * @param len the new length + */ + KSocketAddress& setLength(TQ_UINT16 len); + + /** + * Returns the family of this address. + * @return the family of this address, AF_UNSPEC if it's undefined + */ + int family() const; + + /** + * Sets the family of this object. + * + * Note: setting the family will probably invalidate any address data + * contained in this object. Use this function with care. + * + * @param family the new family to set + */ + virtual KSocketAddress& setFamily(int family); + + /** + * Returns the IANA family number of this address. + * @return the IANA family number of this address (1 for AF_INET. + * 2 for AF_INET6, otherwise 0) + */ + inline int ianaFamily() const + { return ianaFamily(family()); } + + /** + * Returns true if this equals the other socket. + * + * Socket addresses are considered matching if and only if all data is the same. + * + * @param other the other socket + * @return true if both sockets are equal + */ + bool operator ==(const KSocketAddress& other) const; + + /** + * Returns the node name of this socket. + * + * In the case of Internet sockets, this is string representation of the IP address. + * The default implementation returns TQString::null. + * + * @return the node name, can be TQString::null + * @bug use KResolver to resolve unknown families + */ + virtual TQString nodeName() const; + + /** + * Returns the service name for this socket. + * + * In the case of Internet sockets, this is the port number. + * The default implementation returns TQString::null. + * + * @return the service name, can be TQString::null + * @bug use KResolver to resolve unknown families + */ + virtual TQString serviceName() const; + + /** + * Returns this socket address as a string suitable for + * printing. Family, node and service are part of this address. + * + * @bug use KResolver to resolve unknown families + */ + virtual TQString toString() const; + + /** + * Returns an object reference that can be used to manipulate this socket + * as an Internet socket address. Both objects share the same data. + */ + KInetSocketAddress& asInet(); + + /** + * Returns an object is equal to this object's data, but they don't share it. + */ + KInetSocketAddress asInet() const; + + /** + * Returns an object reference that can be used to manipulate this socket + * as a Unix socket address. Both objects share the same data. + */ + KUnixSocketAddress& asUnix(); + + /** + * Returns an object is equal to this object's data, but they don't share it. + */ + KUnixSocketAddress asUnix() const; + +protected: + /// @internal + /// private data + KSocketAddressData *d; + + /// @internal + /// extra constructor + KSocketAddress(KSocketAddressData* d); + +public: // static + /** + * Returns the IANA family number of the given address family. + * Returns 0 if there is no corresponding IANA family number. + * @param af the address family, in AF_* constants + * @return the IANA family number of this address (1 for AF_INET. + * 2 for AF_INET6, otherwise 0) + */ + static int ianaFamily(int af); + + /** + * Returns the address family of the given IANA family number. + * @return the address family, AF_UNSPEC for unknown IANA family numbers + */ + static int fromIanaFamily(int iana); +}; + + +/** @class KInetSocketAddress tdesocketaddress.h tdesocketaddress.h + * @brief an Internet socket address + * + * An Inet (IPv4 or IPv6) socket address + * + * This is an IPv4 or IPv6 address of the Internet. + * + * @author Thiago Macieira + */ +class TDECORE_EXPORT KInetSocketAddress: public KSocketAddress +{ + friend class KSocketAddress; +public: + /** + * Public constructor. Creates an empty object. + */ + KInetSocketAddress(); + + /** + * Creates an object from raw data. + * + * Note: if the socket address @p sa does not contain a valid Internet + * socket (IPv4 or IPv6), this object will be empty. + * + * @param sa the sockaddr structure + * @param len the structure's length + */ + KInetSocketAddress(const sockaddr* sa, TQ_UINT16 len); + + /** + * Creates an object from an IP address and port. + * + * @param host the IP address + * @param port the port number + */ + KInetSocketAddress(const KIpAddress& host, TQ_UINT16 port); + + /** + * Copy constructor. + * + * Data is not shared. + * + * @param other the other object + */ + KInetSocketAddress(const KInetSocketAddress& other); + + /** + * Copy constructor. + * + * If the other, generic socket address contains an Internet address, + * it will be copied. Otherwise, this object will be empty. + * + * @param other the other object + */ + KInetSocketAddress(const KSocketAddress& other); + + /** + * Destroys this object. + */ + virtual ~KInetSocketAddress(); + + /** + * Copy operator. + * + * Copies the other object into this one. + * + * @param other the other object + */ + KInetSocketAddress& operator =(const KInetSocketAddress& other); + + /** + * Cast operator to sockaddr_in. + */ + inline operator const sockaddr_in*() const + { return (const sockaddr_in*)address(); } + + /** + * Cast operator to sockaddr_in6. + */ + inline operator const sockaddr_in6*() const + { return (const sockaddr_in6*)address(); } + + /** + * Returns the IP version of the address this object holds. + * + * @return 4 or 6, if IPv4 or IPv6, respectively; 0 if this object is empty + */ + int ipVersion() const; + + /** + * Returns the IP address component. + */ + KIpAddress ipAddress() const; + + /** + * Sets the IP address to the given raw address. + * + * This call will preserve port numbers accross IP versions, but will lose + * IPv6 specific data if the address is set to IPv4. + * + * @param addr the address to set to + * @return a reference to itself + */ + KInetSocketAddress& setHost(const KIpAddress& addr); + + /** + * Retrieves the port number stored in this object. + * + * @return a port number in the range 0 to 65535, inclusive. An empty or + * invalid object will have a port number of 0. + */ + TQ_UINT16 port() const; + + /** + * Sets the port number. If this object is empty, this function will default to + * creating an IPv4 address. + * + * @param port the port number to set + * @return a reference to itself + */ + KInetSocketAddress& setPort(TQ_UINT16 port); + + /** + * Converts this object to an IPv4 socket address. It has no effect if the object + * is already an IPv4 socket address. + * + * If this object is an IPv6 address, the port number is preserved. All other information + * is lost. + * + * @return a reference to itself + */ + KInetSocketAddress& makeIPv4(); + + /** + * Converts this object to an IPv6 socket address. It has no effect if the object + * is already an IPv6 socket address. + * + * If this object is an IPv4 address, the port number is preserved. + * + * @return a reference to itself + */ + KInetSocketAddress& makeIPv6(); + + /** + * Returns the flowinfo information from the IPv6 socket address. + * + * @return the flowinfo information or 0 if this object is empty or IPv4 + */ + TQ_UINT32 flowinfo() const; + + /** + * Sets the flowinfo information for an IPv6 socket address. If this is not + * an IPv6 socket address, this function converts it to one. See makeIPv6. + * + * @param flowinfo the flowinfo to set + * @return a reference to itself + */ + KInetSocketAddress& setFlowinfo(TQ_UINT32 flowinfo); + + /** + * Returns the scope id this IPv6 socket is bound to. + * + * @return the scope id, or 0 if this is not an IPv6 object + */ + int scopeId() const; + + /** + * Sets the scope id for this IPv6 object. If this is not an IPv6 socket + * address, this function converts it to one. See makeIPv6 + * + * @param scopeid the scopeid to set + * @return a reference to itself + */ + KInetSocketAddress& setScopeId(int scopeid); + +protected: + /// @internal + /// extra constructor + KInetSocketAddress(KSocketAddressData* d); + +private: + void update(); +}; + +/* + * External definition + */ + +/** @class KUnixSocketAddress tdesocketaddress.h tdesocketaddress.h + * @brief A Unix (local) socket address. + * + * This is a Unix socket address. + * + * Note that this class uses QStrings to represent filenames, which means + * the proper encoding is used to translate into valid filesystem file names. + * + * @author Thiago Macieira + */ +class TDECORE_EXPORT KUnixSocketAddress: public KSocketAddress +{ + friend class KSocketAddress; +public: + /** + * Default constructor. Creates an empty object. + */ + KUnixSocketAddress(); + + /** + * Creates this object with the given raw data. If + * the sockaddr structure does not contain a Local namespace + * (Unix) socket, this object will be created empty. + * + * @param sa the socket address structure + * @param len the structure's length + */ + KUnixSocketAddress(const sockaddr* sa, TQ_UINT16 len); + + /** + * Copy constructor. Creates a copy of the other object, + * sharing the data explicitly. + * + * @param other the other object + */ + KUnixSocketAddress(const KUnixSocketAddress& other); + + /** + * Constructs an object from the given pathname. + */ + KUnixSocketAddress(const TQString& pathname); + + /** + * Destructor. + */ + virtual ~KUnixSocketAddress(); + + /** + * Copy operator. Copies the contents of the other object into + * this one. Data is explicitly shared. + * + * @param other the other + */ + KUnixSocketAddress& operator =(const KUnixSocketAddress& other); + + /** + * Cast operator to sockaddr_un. + */ + inline operator const sockaddr_un*() const + { return (const sockaddr_un*)address(); } + + /** + * Returns the pathname associated with this object. Will return + * TQString::null if this object is empty. + */ + TQString pathname() const; + + /** + * Sets the pathname for the object. + * + * @return a reference to itself + */ + KUnixSocketAddress& setPathname(const TQString& path); + +protected: + /// @internal + /// extra constructor + KUnixSocketAddress(KSocketAddressData* d); +}; + +} // namespace KNetwork + +#endif diff --git a/tdecore/network/tdesocketbase.cpp b/tdecore/network/tdesocketbase.cpp new file mode 100644 index 000000000..9be0d6e52 --- /dev/null +++ b/tdecore/network/tdesocketbase.cpp @@ -0,0 +1,327 @@ +/* -*- 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. + */ + +#include +#include +#include "klocale.h" + +#include "tdesocketbase.h" +#include "tdesocketdevice.h" + +using namespace KNetwork; + +class KNetwork::KSocketBasePrivate +{ +public: + int socketOptions; + int socketError; + int capabilities; + + mutable KSocketDevice* device; + + TQMutex mutex; + + KSocketBasePrivate() + : mutex(true) // create recursive + { } +}; + +KSocketBase::KSocketBase() + : d(new KSocketBasePrivate) +{ + d->socketOptions = Blocking; + d->socketError = 0; + d->device = 0L; + d->capabilities = 0; +} + +KSocketBase::~KSocketBase() +{ + delete d->device; + delete d; +} + +bool KSocketBase::setSocketOptions(int opts) +{ + d->socketOptions = opts; + return true; +} + +int KSocketBase::socketOptions() const +{ + return d->socketOptions; +} + +bool KSocketBase::setBlocking(bool enable) +{ + return setSocketOptions((socketOptions() & ~Blocking) | (enable ? Blocking : 0)); +} + +bool KSocketBase::blocking() const +{ + return socketOptions() & Blocking; +} + +bool KSocketBase::setAddressReuseable(bool enable) +{ + return setSocketOptions((socketOptions() & ~AddressReuseable) | (enable ? AddressReuseable : 0)); +} + +bool KSocketBase::addressReuseable() const +{ + return socketOptions() & AddressReuseable; +} + +bool KSocketBase::setIPv6Only(bool enable) +{ + return setSocketOptions((socketOptions() & ~IPv6Only) | (enable ? IPv6Only : 0)); +} + +bool KSocketBase::isIPv6Only() const +{ + return socketOptions() & IPv6Only; +} + +bool KSocketBase::setBroadcast(bool enable) +{ + return setSocketOptions((socketOptions() & ~Broadcast) | (enable ? Broadcast : 0)); +} + +bool KSocketBase::broadcast() const +{ + return socketOptions() & Broadcast; +} + +KSocketDevice* KSocketBase::socketDevice() const +{ + if (d->device) + return d->device; + + // it doesn't exist, so create it + TQMutexLocker locker(mutex()); + if (d->device) + return d->device; + + KSocketBase* that = const_cast(this); + KSocketDevice* dev = 0; + if (d->capabilities) + dev = KSocketDevice::createDefault(that, d->capabilities); + if (!dev) + dev = KSocketDevice::createDefault(that); + that->setSocketDevice(dev); + return d->device; +} + +void KSocketBase::setSocketDevice(KSocketDevice* device) +{ + TQMutexLocker locker(mutex()); + if (d->device == 0L) + d->device = device; +} + +int KSocketBase::setRequestedCapabilities(int add, int remove) +{ + d->capabilities |= add; + d->capabilities &= ~remove; + return d->capabilities; +} + +bool KSocketBase::hasDevice() const +{ + return d->device != 0L; +} + +void KSocketBase::setError(SocketError error) +{ + d->socketError = error; +} + +KSocketBase::SocketError KSocketBase::error() const +{ + return static_cast(d->socketError); +} + +// static +TQString KSocketBase::errorString(KSocketBase::SocketError code) +{ + TQString reason; + switch (code) + { + case NoError: + reason = i18n("Socket error code NoError", "no error"); + break; + + case LookupFailure: + reason = i18n("Socket error code LookupFailure", + "name lookup has failed"); + break; + + case AddressInUse: + reason = i18n("Socket error code AddressInUse", + "address already in use"); + break; + + case AlreadyBound: + reason = i18n("Socket error code AlreadyBound", + "socket is already bound"); + break; + + case AlreadyCreated: + reason = i18n("Socket error code AlreadyCreated", + "socket is already created"); + break; + + case NotBound: + reason = i18n("Socket error code NotBound", + "socket is not bound"); + break; + + case NotCreated: + reason = i18n("Socket error code NotCreated", + "socket has not been created"); + break; + + case WouldBlock: + reason = i18n("Socket error code WouldBlock", + "operation would block"); + break; + + case ConnectionRefused: + reason = i18n("Socket error code ConnectionRefused", + "connection actively refused"); + break; + + case ConnectionTimedOut: + reason = i18n("Socket error code ConnectionTimedOut", + "connection timed out"); + break; + + case InProgress: + reason = i18n("Socket error code InProgress", + "operation is already in progress"); + break; + + case NetFailure: + reason = i18n("Socket error code NetFailure", + "network failure occurred"); + break; + + case NotSupported: + reason = i18n("Socket error code NotSupported", + "operation is not supported"); + break; + + case Timeout: + reason = i18n("Socket error code Timeout", + "timed operation timed out"); + break; + + case UnknownError: + reason = i18n("Socket error code UnknownError", + "an unknown/unexpected error has happened"); + break; + + case RemotelyDisconnected: + reason = i18n("Socket error code RemotelyDisconnected", + "remote host closed connection"); + break; + + default: + reason = TQString::null; + break; + } + + return reason; +} + +// static +bool KSocketBase::isFatalError(int code) +{ + switch (code) + { + case WouldBlock: + case InProgress: + case NoError: + case RemotelyDisconnected: + return false; + } + + return true; +} + +void KSocketBase::unsetSocketDevice() +{ + d->device = 0L; +} + +TQMutex* KSocketBase::mutex() const +{ + return &d->mutex; +} + +KActiveSocketBase::KActiveSocketBase() +{ +} + +KActiveSocketBase::~KActiveSocketBase() +{ +} + +int KActiveSocketBase::getch() +{ + unsigned char c; + if (tqreadBlock((char*)&c, 1) != 1) + return -1; + + return c; +} + +int KActiveSocketBase::putch(int ch) +{ + unsigned char c = (unsigned char)ch; + if (tqwriteBlock((char*)&c, 1) != 1) + return -1; + + return c; +} + +void KActiveSocketBase::setError(int status, SocketError error) +{ + KSocketBase::setError(error); + setStatus(status); +} + +void KActiveSocketBase::resetError() +{ + KSocketBase::setError(NoError); + resetStatus(); +} + +KPassiveSocketBase::KPassiveSocketBase() +{ +} + +KPassiveSocketBase::~KPassiveSocketBase() +{ +} diff --git a/tdecore/network/tdesocketbase.h b/tdecore/network/tdesocketbase.h new file mode 100644 index 000000000..48ae15e05 --- /dev/null +++ b/tdecore/network/tdesocketbase.h @@ -0,0 +1,771 @@ +/* -*- 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 KSocketDevice; + +class KSocketBasePrivate; +/** @class KSocketBase 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 KSocketBase +{ +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. + */ + KSocketBase(); + + /** + * Destructor. + */ + virtual ~KSocketBase(); + + /* + * 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. + */ + KSocketDevice* 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(KSocketDevice* 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 KSocketDevice::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 KSocketDevice::capabilities, for instance) the availability. + * + * @param add mask of @ref KSocketDevice::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 KSocketDevice + void unsetSocketDevice(); + + KSocketBase(const KSocketBase&); + KSocketBase& operator =(const KSocketBase&); + + KSocketBasePrivate *d; + + friend class KSocketDevice; +}; + +/** + * @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 KSocketBase +{ +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, KSocketAddress& 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, KSocketAddress& 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 KSocketAddress& 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 KSocketAddress 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 KSocketAddress peerAddress() const = 0; + + // FIXME KDE 4.0: + // enable this function +#if 0 + /** + * Returns this socket's externally-visible address, if known. + */ + virtual KSocketAddress 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 KSocketBase +{ +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 KSocketAddress localAddress() const = 0; + + /** + * Returns this socket's externally-visible address if known. + */ + virtual KSocketAddress externalAddress() const = 0; + +private: + KPassiveSocketBase(const KPassiveSocketBase&); + KPassiveSocketBase& operator = (const KPassiveSocketBase&); +}; + +} // namespace KNetwork + +#endif diff --git a/tdecore/network/tdesocketbuffer.cpp b/tdecore/network/tdesocketbuffer.cpp new file mode 100644 index 000000000..0ba18b77b --- /dev/null +++ b/tdecore/network/tdesocketbuffer.cpp @@ -0,0 +1,329 @@ +/* -*- C++ -*- + * Copyright (C) 2003 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 +#include + +#include "tdesocketbase.h" +#include "tdesocketbuffer_p.h" + +using namespace KNetwork; +using namespace KNetwork::Internal; + +KSocketBuffer::KSocketBuffer(TQ_LONG size) + : m_mutex(true), m_offset(0), m_size(size), m_length(0) +{ +} + +KSocketBuffer::KSocketBuffer(const KSocketBuffer& other) + : KIOBufferBase(other), m_mutex(true) +{ + *this = other; +} + +KSocketBuffer::~KSocketBuffer() +{ + // TQValueList takes care of deallocating memory +} + +KSocketBuffer& KSocketBuffer::operator=(const KSocketBuffer& other) +{ + TQMutexLocker locker1(&m_mutex); + TQMutexLocker locker2(&other.m_mutex); + + KIOBufferBase::operator=(other); + + m_list = other.m_list; // copy-on-write + m_offset = other.m_offset; + m_size = other.m_size; + m_length = other.m_length; + + return *this; +} + +bool KSocketBuffer::canReadLine() const +{ + TQMutexLocker locker(&m_mutex); + + TQValueListConstIterator it = m_list.constBegin(), + end = m_list.constEnd(); + TQIODevice::Offset offset = m_offset; + + // walk the buffer + for ( ; it != end; ++it) + { + if ((*it).find('\n', offset) != -1) + return true; + if ((*it).find('\r', offset) != -1) + return true; + offset = 0; + } + + return false; // not found +} + +TQCString KSocketBuffer::readLine() +{ + if (!canReadLine()) + return TQCString(); // empty + + TQMutexLocker locker(&m_mutex); + + // find the offset of the newline in the buffer + int newline = 0; + TQValueListConstIterator it = m_list.constBegin(), + end = m_list.constEnd(); + TQIODevice::Offset offset = m_offset; + + // walk the buffer + for ( ; it != end; ++it) + { + int posnl = (*it).find('\n', offset); + if (posnl == -1) + { + // not found in this one + newline += (*it).size(); + offset = 0; + continue; + } + + // we found it + newline += posnl; + break; + } + + TQCString result(newline + 2 - m_offset); + consumeBuffer(result.data(), newline + 1 - m_offset); + return result; +} + +TQ_LONG KSocketBuffer::length() const +{ + return m_length; +} + +TQ_LONG KSocketBuffer::size() const +{ + return m_size; +} + +bool KSocketBuffer::setSize(TQ_LONG size) +{ + m_size = size; + if (size == -1 || m_length < m_size) + return true; + + // size is now smaller than length + TQMutexLocker locker(&m_mutex); + + // repeat the test + if (m_length < m_size) + return true; + + // discard from the beginning + return (m_length - m_size) == consumeBuffer(0L, m_length - m_size, true); +} + +TQ_LONG KSocketBuffer::feedBuffer(const char *data, TQ_LONG len) +{ + if (data == 0L || len == 0) + return 0; // nothing to write + if (isFull()) + return -1; // can't write + + TQMutexLocker locker(&m_mutex); + + // verify if we can add len bytes + if (m_size != -1 && (m_size - m_length) < len) + len = m_size - m_length; + + TQByteArray a(len); + a.duplicate(data, len); + m_list.append(a); + + m_length += len; + return len; +} + +TQ_LONG KSocketBuffer::consumeBuffer(char *destbuffer, TQ_LONG maxlen, bool discard) +{ + if (maxlen == 0 || isEmpty()) + return 0; + + TQValueListIterator it = m_list.begin(), + end = m_list.end(); + TQIODevice::Offset offset = m_offset; + TQ_LONG copied = 0; + + // walk the buffer + while (it != end && maxlen) + { + // calculate how much we'll copy + size_t to_copy = (*it).size() - offset; + if (to_copy > maxlen) + to_copy = maxlen; + + // do the copying + if (destbuffer) + memcpy(destbuffer + copied, (*it).data() + offset, to_copy); + maxlen -= to_copy; + copied += to_copy; + + if ((*it).size() - offset > to_copy) + { + // we did not copy everything + offset += to_copy; + break; + } + else + { + // we copied everything + // discard this element; + offset = 0; + if (discard) + it = m_list.remove(it); + else + ++it; + } + } + + if (discard) + { + m_offset = offset; + m_length -= copied; + assert(m_length >= 0); + } + + return copied; +} + +void KSocketBuffer::clear() +{ + TQMutexLocker locker(&m_mutex); + m_list.clear(); + m_offset = 0; + m_length = 0; +} + +TQ_LONG KSocketBuffer::sendTo(KActiveSocketBase* dev, TQ_LONG len) +{ + if (len == 0 || isEmpty()) + return 0; + + TQMutexLocker locker(&m_mutex); + + TQValueListIterator it = m_list.begin(), + end = m_list.end(); + TQIODevice::Offset offset = m_offset; + TQ_LONG written = 0; + + // walk the buffer + while (it != end && (len || len == -1)) + { + // we have to write each element up to len bytes + // but since we can have several very small buffers, we can make things + // better by concatenating a few of them into a big buffer + // question is: how big should that buffer be? 2 kB should be enough + + TQ_ULONG bufsize = 1460; + if (len != -1 && len < bufsize) + bufsize = len; + TQByteArray buf(bufsize); + TQ_LONG count = 0; + + while (it != end && count + ((*it).size() - offset) <= bufsize) + { + memcpy(buf.data() + count, (*it).data() + offset, (*it).size() - offset); + count += (*it).size() - offset; + offset = 0; + ++it; + } + + // see if we can still fit more + if (count < bufsize && it != end) + { + // getting here means this buffer (*it) is larger than + // (bufsize - count) (even for count == 0). + memcpy(buf.data() + count, (*it).data() + offset, bufsize - count); + offset += bufsize - count; + count = bufsize; + } + + // now try to write those bytes + TQ_LONG wrote = dev->tqwriteBlock(buf, count); + + if (wrote == -1) + // error? + break; + + written += wrote; + if (wrote != count) + // can't fit more? + break; + } + + // discard data that has been written + // this updates m_length too + if (written) + consumeBuffer(0L, written); + + return written; +} + +TQ_LONG KSocketBuffer::receiveFrom(KActiveSocketBase* dev, TQ_LONG len) +{ + if (len == 0 || isFull()) + return 0; + + TQMutexLocker locker(&m_mutex); + + if (len == -1) + len = dev->bytesAvailable(); + if (len <= 0) + // error or closing socket + return len; + + // see if we can read that much + if (m_size != -1 && len > (m_size - m_length)) + len = m_size - m_length; + + // here, len contains just as many bytes as we're supposed to read + + // now do the reading + TQByteArray a(len); + len = dev->tqreadBlock(a.data(), len); + + if (len == -1) + // error? + return -1; + + // success + // resize the buffer and add it + a.truncate(len); + m_list.append(a); + m_length += len; + return len; +} diff --git a/tdecore/network/tdesocketbuffer_p.h b/tdecore/network/tdesocketbuffer_p.h new file mode 100644 index 000000000..b2c5dc6b2 --- /dev/null +++ b/tdecore/network/tdesocketbuffer_p.h @@ -0,0 +1,164 @@ +/* -*- C++ -*- + * Copyright (C) 2003 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. + */ + +#ifndef TDESOCKETBUFFER_P_H +#define TDESOCKETBUFFER_P_H + +#include +#include +#include +#include "kiobuffer.h" + +namespace KNetwork { + +class KActiveSocketBase; + + namespace Internal { + +/** + * @internal + * @class KSocketBuffer tdesocketbuffer_p.h tdesocketbuffer_p.h + * @brief generic socket buffering code + * + * This class implements generic buffering used by @ref KBufferedSocket. + * + * @author Thiago Macieira + */ +class KSocketBuffer: public KIOBufferBase +{ +public: + /** + * Default constructor. + * + * @param size the maximum size of the buffer + */ + KSocketBuffer(TQ_LONG size = -1); + + /** + * Copy constructor. + */ + KSocketBuffer(const KSocketBuffer& other); + + /** + * Virtual destructor. Frees the buffer and discards its contents. + */ + virtual ~KSocketBuffer(); + + /** + * Assignment operator. + */ + KSocketBuffer& operator=(const KSocketBuffer& other); + + /** + * Returns true if a line can be read from the buffer. + */ + virtual bool canReadLine() const; + + /** + * Reads a line from the buffer and discard it from the buffer. + */ + virtual TQCString readLine(); + + /** + * Returns the number of bytes in the buffer. Note that this is not + * the size of the buffer. + * + * @sa size + */ + virtual TQ_LONG length() const; + + /** + * Retrieves the buffer size. The value of -1 indicates that + * the buffer has no defined upper limit. + * + * @sa length for the length of the data stored + */ + virtual TQ_LONG size() const; + + /** + * Sets the size of the buffer, if allowed. + * + * @param size the maximum size, use -1 for unlimited. + * @returns true on success, false if an error occurred. + * @note if the new size is less than length(), the buffer will be truncated + */ + virtual bool setSize(TQ_LONG size); + + /** + * Adds data to the end of the buffer. + * + * @param data the data to be added + * @param len the data length, in bytes + * @returns the number of bytes added to the end of the buffer. + */ + virtual TQ_LONG feedBuffer(const char *data, TQ_LONG len); + + /** + * Clears the buffer. + */ + virtual void clear(); + + /** + * Consumes data from the beginning of the buffer. + * + * @param data where to copy the data to + * @param maxlen the maximum length to copy, in bytes + * @param discard if true, the bytes copied will be discarded + * @returns the number of bytes copied from the buffer + */ + virtual TQ_LONG consumeBuffer(char *data, TQ_LONG maxlen, bool discard = true); + + /** + * Sends at most @p len bytes of data to the I/O Device. + * + * @param device the device to which to send data + * @param len the amount of data to send; -1 to send everything + * @returns the number of bytes sent and discarded from the buffer, -1 + * indicates an error. + */ + virtual TQ_LONG sendTo(KActiveSocketBase* device, TQ_LONG len = -1); + + /** + * Tries to receive @p len bytes of data from the I/O device. + * + * @param device the device to receive from + * @param len the number of bytes to receive; -1 to read as much + * as possible + * @returns the number of bytes received and copied into the buffer, + * -1 indicates an error. + */ + virtual TQ_LONG receiveFrom(KActiveSocketBase* device, TQ_LONG len = -1); + +protected: + mutable TQMutex m_mutex; + TQValueList m_list; + TQIODevice::Offset m_offset; ///< offset of the start of data in the first element + + TQ_LONG m_size; ///< the maximum length of the buffer + mutable TQ_LONG m_length; +}; + +} } // namespace KNetwork::Internal + +#endif diff --git a/tdecore/network/tdesocketdevice.cpp b/tdecore/network/tdesocketdevice.cpp new file mode 100644 index 000000000..064b66b08 --- /dev/null +++ b/tdecore/network/tdesocketdevice.cpp @@ -0,0 +1,891 @@ +/* -*- 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. + */ + +#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::KSocketDevicePrivate +{ +public: + mutable TQSocketNotifier *input, *output, *exception; + KSocketAddress local, peer; + int af; + + inline KSocketDevicePrivate() + { + input = output = exception = 0L; + af = 0; + } +}; + + +KSocketDevice::KSocketDevice(const KSocketBase* parent) + : m_sockfd(-1), d(new KSocketDevicePrivate) +{ + setSocketDevice(this); + if (parent) + setSocketOptions(parent->socketOptions()); +} + +KSocketDevice::KSocketDevice(int fd) + : m_sockfd(fd), d(new KSocketDevicePrivate) +{ + setState(IO_Open); + setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); + setSocketDevice(this); + d->af = localAddress().family(); +} + +KSocketDevice::KSocketDevice(bool, const KSocketBase* parent) + : m_sockfd(-1), d(new KSocketDevicePrivate) +{ + // do not set parent + if (parent) + setSocketOptions(parent->socketOptions()); +} + +KSocketDevice::~KSocketDevice() +{ + close(); // deletes the notifiers + unsetSocketDevice(); // prevent double deletion + delete d; +} + +bool KSocketDevice::setSocketOptions(int opts) +{ + // must call parent + TQMutexLocker locker(mutex()); + KSocketBase::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 KSocketDevice::open(TQ_OpenMode) +{ + resetError(); + return false; +} + +void KSocketDevice::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 KSocketDevice::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 KSocketDevice::create(const KResolverEntry& address) +{ + return create(address.family(), address.socketType(), address.protocol()); +} + +bool KSocketDevice::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 KSocketDevice::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 KSocketDevice::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 +} + +KSocketDevice* KSocketDevice::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 KSocketDevice(newfd); +} + +bool KSocketDevice::disconnect() +{ + resetError(); + + if (m_sockfd == -1) + return false; // can't create + + KSocketAddress 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 KSocketDevice::bytesAvailable() const +#endif +#ifdef USE_QT4 +qint64 KSocketDevice::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 KSocketDevice::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, KSocketAddress* 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 KSocketDevice::WouldBlock; + else + return KSocketDevice::UnknownError; + } + if (retval == 0) + return KSocketDevice::RemotelyDisconnected; + + if (from) + from->setLength(len); + return 0; +} + +TQT_TQIO_LONG KSocketDevice::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 KSocketDevice::tqreadBlock(char *data, TQT_TQIO_ULONG maxlen, KSocketAddress &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 KSocketDevice::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 KSocketDevice::peekBlock(char *data, TQ_ULONG maxlen, KSocketAddress& 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 KSocketDevice::tqwriteBlock(const char *data, TQT_TQIO_ULONG len) +{ + return tqwriteBlock(data, len, KSocketAddress()); +} + +TQT_TQIO_LONG KSocketDevice::tqwriteBlock(const char *data, TQT_TQIO_ULONG len, const KSocketAddress& 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; +} + +KSocketAddress KSocketDevice::localAddress() const +{ + if (m_sockfd == -1) + return KSocketAddress(); // not open, empty value + + if (d->local.family() != AF_UNSPEC) + return d->local; + + socklen_t len; + KSocketAddress localAddress; + localAddress.setLength(len = 32); // arbitrary value + if (kde_getsockname(m_sockfd, localAddress.address(), &len) == -1) + // error! + return d->local = KSocketAddress(); + +#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 = KSocketAddress(); + + return d->local = localAddress; +} + +KSocketAddress KSocketDevice::peerAddress() const +{ + if (m_sockfd == -1) + return KSocketAddress(); // not open, empty value + + if (d->peer.family() != AF_UNSPEC) + return d->peer; + + socklen_t len; + KSocketAddress peerAddress; + peerAddress.setLength(len = 32); // arbitrary value + if (kde_getpeername(m_sockfd, peerAddress.address(), &len) == -1) + // error! + return d->peer = KSocketAddress(); + +#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 = KSocketAddress(); + + return d->peer = peerAddress; +} + +KSocketAddress KSocketDevice::externalAddress() const +{ + // for normal sockets, the externally visible address is the same + // as the local address + return localAddress(); +} + +TQSocketNotifier* KSocketDevice::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* KSocketDevice::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* KSocketDevice::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 KSocketDevice::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 KSocketDevice::poll(int timeout, bool *timedout) +{ + bool input, output, exception; + return poll(&input, &output, &exception, timeout, timedout); +} + +TQSocketNotifier* KSocketDevice::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 KSocketDeviceFactoryBase* defaultImplFactory; +static TQMutex defaultImplFactoryMutex; +typedef TQMap factoryMap; +static factoryMap factories; + +KSocketDevice* KSocketDevice::createDefault(KSocketBase* parent) +{ + KSocketDevice* device = dynamic_cast(parent); + if (device != 0L) + return device; + + KSocksSocketDevice::initSocks(); + + if (defaultImplFactory) + return defaultImplFactory->create(parent); + + // the really default + return new KSocketDevice(parent); +} + +KSocketDevice* KSocketDevice::createDefault(KSocketBase* parent, int capabilities) +{ + KSocketDevice* 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 +} + +KSocketDeviceFactoryBase* +KSocketDevice::setDefaultImpl(KSocketDeviceFactoryBase* factory) +{ + TQMutexLocker locker(&defaultImplFactoryMutex); + KSocketDeviceFactoryBase* old = defaultImplFactory; + defaultImplFactory = factory; + return old; +} + +void KSocketDevice::addNewImpl(KSocketDeviceFactoryBase* factory, int capabilities) +{ + TQMutexLocker locker(&defaultImplFactoryMutex); + if (factories.contains(capabilities)) + delete factories[capabilities]; + factories.insert(capabilities, factory); +} + diff --git a/tdecore/network/tdesocketdevice.h b/tdecore/network/tdesocketdevice.h new file mode 100644 index 000000000..10856716d --- /dev/null +++ b/tdecore/network/tdesocketdevice.h @@ -0,0 +1,433 @@ +/* -*- C++ -*- + * Copyright (C) 2003 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. + */ + +#ifndef TDESOCKETDEVICE_H +#define TDESOCKETDEVICE_H + +#include +#include "tdesocketbase.h" + +namespace KNetwork { + +class KSocketDevice; +class KSocketDeviceFactoryBase; + +class KSocketDevicePrivate; +/** @class KSocketDevice tdesocketdevice.h tdesocketdevice.h + * @brief Low-level socket functionality. + * + * This class provides low-level socket functionality. + * + * Most users will prefer "cooked" interfaces like those of @ref KStreamSocket or + * @ref KServerSocket. + * + * Descended classes from this one provide some other kinds of socket functionality, + * like proxying or specific socket types. + * + * @author Thiago Macieira + */ +class TDECORE_EXPORT KSocketDevice: public KActiveSocketBase, public KPassiveSocketBase +{ +public: + /** + * Capabilities for the socket implementation. + * + * KSocketDevice-derived classes can implement certain capabilities that are not + * available in the default class. These capabilities are described by these flags. + * The default KSocketDevice class has none of these capabilities. + * + * For the negative capabilities (inabilities, the CanNot* forms), when a capability + * is not present, the implementation will default to the original behaviour. + */ + enum Capabilities + { + /** Can connect to hostnames. + * If this flag is present, the string form of @ref connect can be used. */ + CanConnectString = 0x01, + + /** Can bind to hostnames. + * If this flag is present, the string form of @ref bind can be used */ + CanBindString = 0x02, + + /** Can not bind. + * If this flag is present, this implementation cannot bind */ + CanNotBind = 0x04, + + /** Can not listen. + * If this flag is present, this implementation cannot listen */ + CanNotListen = 0x08, + + /** + * Can send multicast as well as join/leave multicast groups. + */ + CanMulticast = 0x10, + + /** + * Can not use datagrams. + * Note that this implies multicast capability not being available either. + */ + CanNotUseDatagrams = 0x20 + }; +protected: + /// The socket file descriptor. It is used throughout the implementation + /// and subclasses. + int m_sockfd; + +public: + /** + * Default constructor. + * + * The parameter is used to specify which socket this object is used as + * a device for. + */ + explicit KSocketDevice(const KSocketBase* = 0L); + + /** + * Constructs a new object around an already-open socket. + * + * Note: you should write programs that create sockets through + * the classes whenever possible. + */ + explicit KSocketDevice(int fd); + + /** + * Destructor. This closes the socket if it's open. + */ + virtual ~KSocketDevice(); + + /** + * Returns the file descriptor for this socket. + */ + inline int socket() const + { return m_sockfd; } + + /** + * Returns the set of capabilities this socket class implements. + * The set of capabilities is defined as an OR-ed mask of + * @ref Capabilities bits. + * + * The default implementation is guaranteed to always return 0. That + * is, derived implementations always return bits where they differ + * from the system standard sockets. + */ + virtual int capabilities() const + { return 0; } + + /** + * This implementation sets the options on the socket. + */ + virtual bool setSocketOptions(int opts); + + /** + * Reimplementation from TQIODevice. You should not call this function in sockets. + */ + virtual bool open(TQ_OpenMode mode); + + /** + * Closes the socket. Reimplemented from TQIODevice. + * + * Use this function to close the socket this object is holding open. + */ + virtual void close(); + + /** + * This call is not supported on sockets. Reimplemented from TQIODevice. + */ + virtual void flush() + { } + + /** + * Creates a socket but don't connect or bind anywhere. + * This function is the equivalent of the system call socket(2). + */ + virtual bool create(int family, int type, int protocol); + + /** + * @overload + * Creates a socket but don't connect or bind anywhere. + */ + bool create(const KResolverEntry& address); + + /** + * Binds this socket to the given address. + */ + virtual bool bind(const KResolverEntry& address); + + /** + * Puts this socket into listening mode. + */ + virtual bool listen(int backlog = 5); // 5 is arbitrary + + /** + * Connect to a remote host. + */ + virtual bool connect(const KResolverEntry& address); + + /** + * Accepts a new incoming connection. + * Note: this function returns a socket of type KSocketDevice. + */ + virtual KSocketDevice* accept(); + + /** + * Disconnects this socket. + */ + virtual bool disconnect(); + + /** + * Returns the number of bytes available for reading without blocking. + */ +#ifdef USE_QT3 + virtual TQ_LONG bytesAvailable() const; +#endif +#ifdef USE_QT4 + virtual qint64 bytesAvailable() const; +#endif + + /** + * Waits up to @p msecs for more data to be available on this socket. + * + * This function is a wrapper against @ref poll. This function will wait + * for any read events. + */ + virtual TQ_LONG waitForMore(int msecs, bool *timeout = 0L); + + /** + * Reads data from this socket. + */ + virtual TQT_TQIO_LONG tqreadBlock(char *data, TQT_TQIO_ULONG maxlen); + + /** + * Reads data and the source address from this socket. + */ + virtual TQT_TQIO_LONG tqreadBlock(char *data, TQT_TQIO_ULONG maxlen, KSocketAddress& from); + + /** + * Peeks data in the socket. + */ + virtual TQ_LONG peekBlock(char *data, TQ_ULONG maxlen); + + /** + * Peeks the data in the socket and the source address. + */ + virtual TQ_LONG peekBlock(char *data, TQ_ULONG maxlen, KSocketAddress& from); + + /** + * Writes data to the socket. + */ + virtual TQT_TQIO_LONG tqwriteBlock(const char *data, TQT_TQIO_ULONG len); + + /** + * Writes the given data to the given destination address. + */ + virtual TQT_TQIO_LONG tqwriteBlock(const char *data, TQT_TQIO_ULONG len, const KSocketAddress& to); + + /** + * Returns this socket's local address. + */ + virtual KSocketAddress localAddress() const; + + /** + * Returns this socket's peer address. If this implementation does proxying + * of some sort, this is the real external address, not the proxy's address. + */ + virtual KSocketAddress peerAddress() const; + + /** + * Returns this socket's externally visible local address. + * + * If this socket has a local address visible externally different + * from the normal local address (as returned by @ref localAddress), then + * return it. + * + * Certain implementations will use proxies and thus have externally visible + * addresses different from the local socket values. The default implementation + * returns the same value as @ref localAddress. + * + * @note This function may return an empty KSocketAddress. In that case, the + * externally visible address could/can not be determined. + */ + virtual KSocketAddress externalAddress() const; + + /** + * Returns a socket notifier for input on this socket. + * The notifier is created only when requested. Whether + * it is enabled or not depends on the implementation. + * + * This function might return NULL. + */ + TQSocketNotifier* readNotifier() const; + + /** + * Returns a socket notifier for output on this socket. + * The is created only when requested. + * + * This function might return NULL. + */ + TQSocketNotifier* writeNotifier() const; + + /** + * Returns a socket notifier for exceptional events on this socket. + * The is created only when requested. + * + * This function might return NULL. + */ + TQSocketNotifier* exceptionNotifier() const; + + /** + * Executes a poll in the socket, via select(2) or poll(2). + * The events polled are returned in the parameters pointers. + * Set any of them to NULL to disable polling of that event. + * + * On exit, @p input, @p output and @p exception will contain + * true if an event of that kind is waiting on the socket or false + * if not. If a timeout occurred, set @p timedout to true (all other + * parameters are necessarily set to false). + * + * @param input if set, turns on polling for input events + * @param output if set, turns on polling for output events + * @param exception if set, turns on polling for exceptional events + * @param timeout the time in milliseconds to wait for an event; + * 0 for no wait and any negative value to wait forever + * @param timedout on exit, will contain true if the polling timed out + * @return true if the poll call succeeded and false if an error occurred + */ + virtual bool poll(bool* input, bool* output, bool* exception = 0L, + int timeout = -1, bool* timedout = 0L); + + /** + * Shorter version to poll for any events in a socket. This call + * polls for input, output and exceptional events in a socket but + * does not return their states. This is useful if you need to wait for + * any event, but don't need to know which; or for timeouts. + * + * @param timeout the time in milliseconds to wait for an event; + * 0 for no wait and any negative value to wait forever + * @param timedout on exit, will contain true if the polling timed out + * @return true if the poll call succeeded and false if an error occurred + */ + bool poll(int timeout = -1, bool* timedout = 0L); + +protected: + /** + * Special constructor. This constructor will cause the internal + * socket device NOT to be set. Use this if your socket device class + * takes another underlying socket device. + * + * @param parent the parent, if any + */ + KSocketDevice(bool, const KSocketBase* parent = 0L); + + /** + * Creates a socket notifier of the given type. + * + * This function is called by @ref readNotifier, @ref writeNotifier and + * @ref exceptionNotifier when they need to create a socket notifier + * (i.e., the first call to those functions after the socket is open). + * After that call, those functions cache the socket notifier and will + * not need to call this function again. + * + * Reimplement this function in your derived class if your socket type + * requires a different kind of TQSocketNotifier. The return value should + * be deleteable with delete. (@ref close deletes them). + * + * @param type the socket notifier type + */ + virtual TQSocketNotifier* createNotifier(TQSocketNotifier::Type type) const; + +public: + /** + * Creates a new default KSocketDevice object given + * the parent object. + * + * The capabilities flag indicates the desired capabilities the object being + * created should possess. Those capabilities are not guaranteed: if no factory + * can provide such an object, a default object will be created. + * + * @param parent the KSocketBase parent + */ + static KSocketDevice* createDefault(KSocketBase* parent); + + /** + * @overload + * + * This will create an object only if the requested capabilities match. + * + * @param parent the parent + * @param capabilities the requested capabilities + */ + static KSocketDevice* createDefault(KSocketBase* parent, int capabilities); + + /** + * Sets the default KSocketDevice implementation to use and + * return the old factory. + * + * @param factory the factory object for the implementation + */ + static KSocketDeviceFactoryBase* setDefaultImpl(KSocketDeviceFactoryBase* factory); + + /** + * Adds a factory of KSocketDevice objects to the list, along with its + * capabilities flag. + */ + static void addNewImpl(KSocketDeviceFactoryBase* factory, int capabilities); + +private: + KSocketDevice(const KSocketDevice&); + KSocketDevice& operator=(const KSocketDevice&); + + KSocketDevicePrivate *d; +}; + +/** @internal + * This class provides functionality for creating and registering + * socket implementations. + */ +class KSocketDeviceFactoryBase +{ +public: + KSocketDeviceFactoryBase() {} + virtual ~KSocketDeviceFactoryBase() {} + + virtual KSocketDevice* create(KSocketBase*) const = 0; +}; + +/** + * This class provides functionality for creating and registering + * socket implementations. + */ +template +class KSocketDeviceFactory: public KSocketDeviceFactoryBase +{ +public: + KSocketDeviceFactory() {} + virtual ~KSocketDeviceFactory() {} + + virtual KSocketDevice* create(KSocketBase* parent) const + { return new Impl(parent); } +}; + +} // namespaces + +#endif -- cgit v1.2.1