summaryrefslogtreecommitdiffstats
path: root/kdecore/ksockaddr.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch)
tree5ac38a06f3dde268dc7927dc155896926aaf7012 /kdecore/ksockaddr.cpp
downloadtdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz
tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdecore/ksockaddr.cpp')
-rw-r--r--kdecore/ksockaddr.cpp894
1 files changed, 894 insertions, 0 deletions
diff --git a/kdecore/ksockaddr.cpp b/kdecore/ksockaddr.cpp
new file mode 100644
index 000000000..be3e08b58
--- /dev/null
+++ b/kdecore/ksockaddr.cpp
@@ -0,0 +1,894 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2000-2002 Thiago Macieira <thiago.macieira@kdemail.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "ksockaddr.h"
+#include <config.h>
+
+#include <sys/types.h>
+
+#ifdef Q_OS_UNIX
+#include <arpa/inet.h>
+#endif
+#include <netinet/in.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <qglobal.h>
+#include <qfile.h>
+
+#include "kdebug.h"
+#include "klocale.h"
+//#include "kextsock.h"
+
+#ifndef HAVE_STRUCT_SOCKADDR_IN6
+// The system doesn't have sockaddr_in6
+// But we can tell netsupp.h to define it for us, according to the RFC
+#define CLOBBER_IN6
+#endif
+
+#include "netsupp.h"
+
+#define V6_CAN_CONVERT_TO_V4(addr) (KDE_IN6_IS_ADDR_V4MAPPED(addr) || KDE_IN6_IS_ADDR_V4COMPAT(addr))
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+# define MY_MAX(a, b) ((a) > (b) ? (a) : (b))
+# define MIN_SOCKADDR_LEN MY_MAX(offsetof(sockaddr, sa_family) + sizeof(((sockaddr*)0)->sa_family), \
+ offsetof(sockaddr, sa_len) + sizeof(((sockaddr*)0)->sa_len))
+#else
+# define MIN_SOCKADDR_LEN (offsetof(sockaddr, sa_family) + sizeof(((sockaddr*)0)->sa_family))
+#endif
+
+// Minimum size accepted for sockaddr_in6 sockets.
+// The scopeid field is missing from some implementations
+// that conform to the obsoleted RFC 2133, e.g. Linux glibc 2.1
+#define MIN_SOCKADDR_IN6_LEN (offsetof(sockaddr_in6, sin6_addr) + sizeof(((sockaddr_in6*)0)->sin6_addr))
+
+#ifdef offsetof
+#undef offsetof
+#endif
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+// This is how it is
+// 46 == strlen("1234:5678:9abc:def0:1234:5678:255.255.255.255")
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+
+/**
+ * Class KSocketAddress
+ */
+
+KSocketAddress::KSocketAddress(const sockaddr* sa, ksocklen_t size)
+{
+ if ( !sa )
+ init();
+ else {
+ data = (sockaddr*)malloc(size);
+ if (data == NULL)
+ return;
+ memcpy(data, sa, size);
+ datasize = size;
+ owndata = true;
+ }
+}
+
+void KSocketAddress::init()
+{
+ data = NULL;
+ datasize = 0;
+ owndata = false;
+}
+
+KSocketAddress::~KSocketAddress()
+{
+ if (owndata && data != NULL)
+ free(data);
+}
+
+QString KSocketAddress::pretty() const
+{
+ return i18n("<unknown socket>");
+}
+
+int KSocketAddress::family() const
+{
+ if (data != NULL)
+ return data->sa_family;
+ return AF_UNSPEC;
+}
+
+// This creates a new KSocketAddress with given sockaddr
+KSocketAddress* KSocketAddress::newAddress(const struct sockaddr* sa, ksocklen_t size)
+{
+ if (size == 0)
+ {
+ kdWarning() << "KSocketAddress::newAddress called with size = 0!\n";
+ return NULL;
+ }
+
+ // make sure we have the right stuff
+ if (size < MIN_SOCKADDR_LEN)
+ {
+ kdWarning() << "KSocketAddress::newAddress called with invalid size\n";
+ return NULL;
+ }
+
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (size >= sizeof(sockaddr_in))
+ return new KInetSocketAddress((const sockaddr_in*)sa, size);
+ return NULL;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ if (size >= MIN_SOCKADDR_IN6_LEN)
+ return new KInetSocketAddress((const sockaddr_in6*)sa, size);
+ return NULL;
+#endif
+
+ case AF_UNIX: // AF_LOCAL
+ return new KUnixSocketAddress((const sockaddr_un*)sa, size);
+ }
+
+ return new KSocketAddress(sa, size);
+}
+
+bool KSocketAddress::isEqual(const KSocketAddress& other) const
+{
+ switch(family())
+ {
+ case AF_INET:
+ return KInetSocketAddress::areEqualInet(*this, other, false);
+#ifdef AF_INET6
+ case AF_INET6:
+ return KInetSocketAddress::areEqualInet6(*this, other, false);
+#endif
+ case AF_UNIX: // AF_LOCAL
+ return KUnixSocketAddress::areEqualUnix(*this, other, false);
+ }
+
+ // This is not a known socket type
+ if (other.datasize != datasize)
+ return false; // can't be equal
+ return memcmp(data, other.data, datasize) == 0;
+}
+
+bool KSocketAddress::isCoreEqual(const KSocketAddress& other) const
+{
+ switch(family())
+ {
+ case AF_INET:
+ return KInetSocketAddress::areEqualInet(*this, other, true);
+#ifdef AF_INET6
+ case AF_INET6:
+ return KInetSocketAddress::areEqualInet6(*this, other, true);
+#endif
+ case AF_UNIX: // AF_LOCAL
+ return KUnixSocketAddress::areEqualUnix(*this, other, true);
+ }
+
+ return false;
+}
+
+QString KSocketAddress::nodeName() const
+{
+ return QString::null;
+}
+
+QString KSocketAddress::serviceName() const
+{
+ return QString::null;
+}
+
+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;
+ }
+}
+
+/**
+ * class KInetSocketAddress
+ */
+class KInetSocketAddressPrivate
+{
+public:
+ int sockfamily;
+ sockaddr_in sin;
+#ifdef AF_INET6
+ sockaddr_in6 sin6;
+#endif
+
+ KInetSocketAddressPrivate() :
+ sockfamily(AF_UNSPEC)
+ {
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin.sin_len = sizeof(sin);
+#endif
+#ifdef AF_INET6
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = 0;
+ sin6.sin6_flowinfo = 0;
+# ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+ sin6.sin6_scope_id = 0;
+# endif
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6.sin6_len = sizeof(sin6);
+# endif
+#endif
+ }
+
+};
+
+KInetSocketAddress::KInetSocketAddress() :
+ d(new KInetSocketAddressPrivate)
+{
+}
+
+KInetSocketAddress::KInetSocketAddress(const KInetSocketAddress &other) :
+ KSocketAddress(), d(new KInetSocketAddressPrivate)
+{
+ setAddress(other);
+}
+
+KInetSocketAddress::KInetSocketAddress(const sockaddr_in* sin, ksocklen_t len) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(sin, len);
+}
+
+KInetSocketAddress::KInetSocketAddress(const sockaddr_in6* sin6, ksocklen_t len) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(sin6, len);
+}
+
+KInetSocketAddress::KInetSocketAddress(const in_addr& addr, unsigned short port) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(addr, port);
+}
+
+KInetSocketAddress::KInetSocketAddress(const in6_addr& addr, unsigned short port) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(addr, port);
+}
+
+KInetSocketAddress::KInetSocketAddress(const QString& addr, unsigned short port, int family) :
+ d(new KInetSocketAddressPrivate)
+{
+ setAddress(addr, port, family);
+}
+
+KInetSocketAddress::~KInetSocketAddress()
+{
+ delete d;
+
+ // KSocketAddress::~KSocketAddress();
+}
+
+bool KInetSocketAddress::setAddress(const KInetSocketAddress &other)
+{
+ if (other.family() == AF_INET)
+ return setAddress(other.addressV4(), other.size());
+#ifdef AF_INET6
+ else if (other.family() == AF_INET6)
+ return setAddress(other.addressV6(), other.size());
+#endif
+ return false;
+}
+
+bool KInetSocketAddress::setAddress(const sockaddr_in* sin, ksocklen_t len)
+{
+ // This is supposed to be a AF_INET socket
+ if ((len < sizeof(sockaddr_in)) || (sin->sin_family != AF_INET))
+ {
+ kdWarning() << "KInetSocketAddress::setAddress(sockaddr_in*) called with invalid sockaddr_in\n";
+ return false;
+ }
+
+ return setHost(sin->sin_addr) && setPort(ntohs(sin->sin_port));
+}
+
+bool KInetSocketAddress::setAddress(const sockaddr_in6* sin6, ksocklen_t len)
+{
+#ifdef AF_INET6
+ // should be family AF_INET6
+ if ((len < MIN_SOCKADDR_IN6_LEN) || (sin6->sin6_family != AF_INET6))
+ {
+ kdWarning() << "KInetSocketAddress::setAddress(sockaddr_in6*) called with invalid sockaddr_in6\n";
+ return 0;
+ }
+
+ memset(&d->sin6, 0, sizeof(d->sin6));
+ if (len > sizeof(d->sin6))
+ len = sizeof(d->sin6);
+ memcpy(&d->sin6, sin6, len);
+
+ /* Now make a sanity check */
+ d->sockfamily = d->sin6.sin6_family = AF_INET6;
+# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ d->sin6.sin6_len = sizeof(d->sin6);
+# endif
+
+ fromV6();
+ return true;
+#else // !AF_INET6
+ return false;
+#endif
+}
+
+bool KInetSocketAddress::setAddress(const in_addr& addr, unsigned short port)
+{
+ return setHost(addr) && setPort(port);
+}
+
+bool KInetSocketAddress::setAddress(const in6_addr& addr, unsigned short port)
+{
+ return setHost(addr) && setPort(port);
+}
+
+bool KInetSocketAddress::setAddress(const QString& addr, unsigned short port, int family)
+{
+ return setHost(addr, family) && setPort(port);
+}
+
+bool KInetSocketAddress::setHost(const in_addr& addr)
+{
+ d->sockfamily = AF_INET; // set address to IPv4 type
+ d->sin.sin_addr = addr;
+ fromV4();
+ return true;
+}
+
+bool KInetSocketAddress::setHost(const in6_addr& addr)
+{
+#ifdef AF_INET6
+ d->sockfamily = AF_INET6; // set address to IPv6 type
+ d->sin6.sin6_addr = addr;
+ fromV6();
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool KInetSocketAddress::setHost(const QString& addr, int family)
+{
+ // if family == -1, we'll try to guess the host name
+ if ((family != -1) && (family != AF_INET)
+#ifdef AF_INET6
+ && (family != AF_INET6)
+#endif
+ )
+ {
+ kdWarning() << "KInetSocketAddress::setHost(QString, int) called with unknown family address\n";
+ return false;
+ }
+
+ if (family == -1)
+ {
+ // guess the family type
+
+#ifdef AF_INET6
+ // IPv6 addresses MUST contain colons (:) and IPv4 addresses must not
+ if (addr.find(':') != -1)
+ family = AF_INET6;
+ else
+ family = AF_INET;
+#else
+
+ // There's only one guess:
+ family = AF_INET;
+#endif
+ }
+
+ /*
+ * FIXME! What is the decoding process for hostnames?
+ */
+ if (family == AF_INET)
+ {
+ inet_pton(family, addr.latin1(), (void*)&(d->sin.sin_addr));
+ fromV4();
+ }
+#ifdef AF_INET6
+ else
+ {
+ inet_pton(family, addr.latin1(), (void*)&(d->sin6.sin6_addr));
+ fromV6();
+ }
+#endif
+ d->sockfamily = family;
+ return true;
+}
+
+bool KInetSocketAddress::setPort(unsigned short port)
+{
+ // set port on all socket types
+ d->sin.sin_port = htons(port);
+#ifdef AF_INET6
+ d->sin6.sin6_port = htons(port);
+#endif
+
+ return true;
+}
+
+bool KInetSocketAddress::setFamily(int _family)
+{
+ if (_family != AF_INET
+#ifdef AF_INET6
+ && _family != AF_INET6
+#endif
+ )
+ {
+ kdWarning() << "KInetSocketAddress::setFamily(int) called with unknown family\n";
+ return false;
+ }
+
+ d->sockfamily = _family;
+ if (_family == AF_INET)
+ fromV4();
+#ifdef AF_INET6
+ else if (_family == AF_INET6)
+ fromV6();
+#endif
+
+ return true;
+}
+
+bool KInetSocketAddress::setFlowinfo(Q_UINT32 flowinfo)
+{
+#ifdef AF_INET6
+ if (d->sockfamily == AF_INET6)
+ {
+ d->sin6.sin6_flowinfo = flowinfo;
+ return true;
+ }
+#endif
+ return false;
+}
+
+bool KInetSocketAddress::setScopeId(int scopeid)
+{
+#if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ if (d->sockfamily == AF_INET6)
+ {
+ d->sin6.sin6_scope_id = scopeid;
+ return true;
+ }
+#endif
+ (void)scopeid;
+ return false;
+}
+
+const sockaddr_in* KInetSocketAddress::addressV4() const
+{
+ if (d->sockfamily == AF_INET)
+ return &d->sin;
+#ifdef AF_INET6
+ else if (d->sockfamily == AF_INET6)
+ {
+ // check if this IPv6 address was converted without loss
+ if (V6_CAN_CONVERT_TO_V4(&d->sin6.sin6_addr))
+ return &d->sin;
+ else
+ return NULL; // there was loss, so return nothing
+ }
+#endif
+
+ kdWarning() << "KInetSocketAddress::addressV4() called on uninitialized socket\n";
+ return NULL;
+}
+
+const sockaddr_in6* KInetSocketAddress::addressV6() const
+{
+#ifdef AF_INET6
+ return &d->sin6;
+#else
+ return NULL;
+#endif
+}
+
+in_addr KInetSocketAddress::hostV4() const
+{
+ // this might be empty
+ return d->sin.sin_addr;
+}
+
+/*
+ * ATTENTION
+ * This function is left undefined if no IPv6 support exists
+ * This is intentional
+ */
+#ifdef AF_INET6
+in6_addr KInetSocketAddress::hostV6() const
+{
+ return d->sin6.sin6_addr;
+}
+#endif
+
+QString KInetSocketAddress::pretty() const
+{
+ if (d->sockfamily != AF_INET
+#ifdef AF_INET6
+ && d->sockfamily != AF_INET6
+#endif
+ )
+ {
+ kdWarning() << "KInetSocketAddress::pretty() called on uninitialized class\n";
+ return i18n("<empty>");
+ }
+
+ return i18n("1: hostname, 2: port number", "%1 port %2").arg(nodeName()).arg(serviceName());
+}
+
+QString KInetSocketAddress::nodeName() const
+{
+ char buf[INET6_ADDRSTRLEN]; // INET6_ADDRSTRLEN > INET_ADDRSTRLEN
+
+ if (d->sockfamily == AF_INET)
+ inet_ntop(d->sockfamily, (void*)&d->sin.sin_addr, buf, sizeof(buf));
+#ifdef AF_INET6
+ else if (d->sockfamily == AF_INET6)
+ inet_ntop(d->sockfamily, (void*)&d->sin6.sin6_addr, buf, sizeof(buf));
+#endif
+ else
+ {
+ kdWarning() << "KInetSocketAddress::nodeName() called on uninitialized class\n";
+ return i18n("<empty>");
+ }
+
+ return QString::fromLatin1(buf); // FIXME! What's the encoding?
+}
+
+QString KInetSocketAddress::serviceName() const
+{
+ return QString::number(port());
+}
+
+unsigned short KInetSocketAddress::port() const
+{
+#ifdef AF_INET6
+ // we prefer sin6 here because fromV6() might make sin.sin_port be 0
+ return ntohs(d->sin6.sin6_port);
+#else
+ return ntohs(d->sin.sin_port);
+#endif
+}
+
+Q_UINT32 KInetSocketAddress::flowinfo() const
+{
+#ifdef AF_INET6
+ if (d->sockfamily == AF_INET6)
+ return (Q_UINT32)d->sin6.sin6_flowinfo;
+#endif
+ return 0;
+}
+
+ksocklen_t KInetSocketAddress::size() const
+{
+ if (d->sockfamily == AF_INET)
+ return sizeof(d->sin);
+#ifdef AF_INET6
+ else if (d->sockfamily == AF_INET6)
+ return sizeof(d->sin6);
+#endif
+ else
+ return 0;
+}
+
+bool KInetSocketAddress::areEqualInet(const KSocketAddress &s1, const KSocketAddress &s2, bool coreOnly)
+{
+ if (s1.family() != s2.family())
+ return false;
+ if ((s1.size() < sizeof(sockaddr_in)) || (s2.size() < sizeof(sockaddr_in)))
+ return false;
+
+ struct sockaddr_in *sin1 = (sockaddr_in *) s1.address();
+ struct sockaddr_in *sin2 = (sockaddr_in *) s2.address();
+
+ if (coreOnly)
+ return (memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof(struct in_addr)) == 0);
+ else
+ return (sin1->sin_port == sin2->sin_port) &&
+ (memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof(struct in_addr)) == 0);
+}
+
+bool KInetSocketAddress::areEqualInet6(const KSocketAddress &s1, const KSocketAddress &s2, bool coreOnly)
+{
+#ifdef AF_INET6
+ if (s1.family() != s2.family())
+ return false;
+
+ if ((s1.size() < sizeof(sockaddr_in6)) || (s2.size() < sizeof(sockaddr_in6)))
+ return false;
+
+ struct sockaddr_in6 *sin1 = (sockaddr_in6 *) s1.address();
+ struct sockaddr_in6 *sin2 = (sockaddr_in6 *) s2.address();
+
+ if (coreOnly)
+ return (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof(struct in6_addr)) == 0);
+ else
+ return (sin1->sin6_port == sin2->sin6_port) &&
+ (sin1->sin6_flowinfo == sin2->sin6_flowinfo) &&
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+ (sin1->sin6_scope_id == sin2->sin6_scope_id) &&
+#endif
+ (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof(struct in6_addr)) == 0);
+#else
+ return false;
+#endif
+}
+
+void KInetSocketAddress::fromV4()
+{
+ // converts an address from v4
+
+#ifdef AF_INET6
+ d->sin6.sin6_port = d->sin.sin_port;
+
+ // Make this a v4-mapped address
+ ((Q_UINT32*)&d->sin6.sin6_addr)[0] = ((Q_UINT32*)&d->sin6.sin6_addr)[1] = 0;
+ ((Q_UINT32*)&d->sin6.sin6_addr)[2] = htonl(0xffff);
+ ((Q_UINT32*)&d->sin6.sin6_addr)[3] = *(Q_UINT32*)&d->sin.sin_addr;
+
+ // Clear flowinfo and scopeid
+ d->sin6.sin6_flowinfo = 0;
+# ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+ d->sin6.sin6_scope_id = 0;
+# endif
+#endif
+
+ // data == KSocketAddress::data
+ data = (sockaddr*)&d->sin;
+ datasize = sizeof( sockaddr_in );
+}
+
+void KInetSocketAddress::fromV6()
+{
+#ifdef AF_INET6
+ // convert to v4 only if this is a v4-mapped or v4-compat address
+ if (V6_CAN_CONVERT_TO_V4(&d->sin6.sin6_addr))
+ {
+ d->sin.sin_port = d->sin6.sin6_port;
+ *(Q_UINT32*)&d->sin.sin_addr = ((Q_UINT32*)&d->sin6.sin6_addr)[3];
+ }
+ else
+ {
+ d->sin.sin_port = 0;
+ memset(&d->sin.sin_addr, 0, sizeof(d->sin.sin_addr));
+ }
+
+ data = (sockaddr*)&d->sin6;
+ datasize = sizeof( d->sin6 );
+#endif
+}
+
+QString KInetSocketAddress::addrToString(int family, const void* addr)
+{
+ char buf[INET6_ADDRSTRLEN+1];
+
+ return QString::fromLatin1(inet_ntop(family, addr, buf, INET6_ADDRSTRLEN));
+}
+
+bool KInetSocketAddress::stringToAddr(int family, const char *text, void *dest)
+{
+ return inet_pton(family, text, dest) != 0;
+}
+
+/**
+ * class KUnixSocketAddress
+ */
+
+class KUnixSocketAddressPrivate
+{
+public:
+ sockaddr_un *m_sun;
+
+ KUnixSocketAddressPrivate() : m_sun(NULL)
+ { }
+};
+
+KUnixSocketAddress::KUnixSocketAddress() :
+ d(new KUnixSocketAddressPrivate)
+{
+}
+
+KUnixSocketAddress::KUnixSocketAddress(const sockaddr_un* _sun, ksocklen_t size) :
+ d(new KUnixSocketAddressPrivate)
+{
+ setAddress(_sun, size);
+}
+
+KUnixSocketAddress::KUnixSocketAddress(QCString pathname) :
+ d(new KUnixSocketAddressPrivate)
+{
+ setAddress(pathname);
+}
+
+KUnixSocketAddress::~KUnixSocketAddress()
+{
+ delete d;
+}
+
+bool KUnixSocketAddress::setAddress(const sockaddr_un* _sun, ksocklen_t _size)
+{
+ if (_sun->sun_family != AF_UNIX)
+ {
+ kdWarning() << "KUnixSocketAddress::setAddress called with invalid socket\n";
+ return false;
+ }
+
+ if (owndata && (d->m_sun != NULL) && (datasize >= _size))
+ {
+ // reuse this without reallocating
+ memcpy(d->m_sun, _sun, _size);
+ }
+ else
+ {
+ if (owndata && (d->m_sun != NULL))
+ free(d->m_sun);
+
+ d->m_sun = (sockaddr_un*)malloc(_size);
+
+ if (d->m_sun == NULL)
+ {
+ // problems
+ owndata = false;
+ return false;
+ }
+
+ memcpy(d->m_sun, _sun, _size);
+ }
+
+ datasize = _size;
+ data = (sockaddr*)d->m_sun;
+ owndata = true;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ data->sa_len = _size;
+#endif
+ return 1;
+}
+
+bool KUnixSocketAddress::setAddress(QCString path)
+{
+ // the +1 is necessary for the ending zero
+ ksocklen_t newsize = offsetof(sockaddr_un, sun_path) + path.length() + 1;
+
+ if (owndata && (d->m_sun != NULL) && (datasize >= newsize))
+ {
+ // we can reuse this
+ strcpy(d->m_sun->sun_path, path);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ data->sa_len = newsize;
+#endif
+ return true;
+ }
+
+ // nah, we have to do better
+ if (owndata && (d->m_sun != NULL))
+ free(d->m_sun);
+
+ d->m_sun = (sockaddr_un*) malloc(newsize);
+ if (d->m_sun == NULL)
+ {
+ owndata = false;
+ return false;
+ }
+
+ d->m_sun->sun_family = AF_UNIX;
+ strcpy(d->m_sun->sun_path, path);
+ data = (sockaddr*)d->m_sun;
+ datasize = newsize;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ data->sa_len = newsize;
+#endif
+ return 1;
+}
+
+QCString KUnixSocketAddress::pathname() const
+{
+ if (d->m_sun != NULL)
+ {
+ if (datasize > offsetof(sockaddr_un, sun_path))
+ return d->m_sun->sun_path;
+ return "";
+ }
+ return QCString(0);
+}
+
+QString KUnixSocketAddress::pretty() const
+{
+ QCString pname = pathname();
+ if (pname.isEmpty())
+ return i18n("<empty UNIX socket>");
+ return QFile::decodeName(pathname());
+}
+
+QString KUnixSocketAddress::serviceName() const
+{
+ return QString::fromUtf8(pathname());
+}
+
+const sockaddr_un* KUnixSocketAddress::address() const
+{
+ return d->m_sun;
+}
+
+bool KUnixSocketAddress::areEqualUnix(const KSocketAddress &s1, const KSocketAddress &s2, bool /* coreOnly */)
+{
+ if (s1.family() != s2.family())
+ return false;
+
+ if ((s1.size() < MIN_SOCKADDR_LEN) || (s2.size() < MIN_SOCKADDR_LEN))
+ return false;
+
+ struct sockaddr_un *sun1 = (sockaddr_un *) s1.address();
+ struct sockaddr_un *sun2 = (sockaddr_un *) s2.address();
+
+ if (s1.size() == MIN_SOCKADDR_LEN && s2.size() == MIN_SOCKADDR_LEN)
+ return true; // unnamed Unix sockets
+
+ return (strcmp(sun1->sun_path, sun2->sun_path) == 0);
+}
+
+void KSocketAddress::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void KInetSocketAddress::virtual_hook( int id, void* data )
+{ KSocketAddress::virtual_hook( id, data ); }
+
+void KUnixSocketAddress::virtual_hook( int id, void* data )
+{ KSocketAddress::virtual_hook( id, data ); }
+
+
+#include "ksockaddr.moc"