File indexing completed on 2024-03-24 15:27:07

0001 /*  -*- C++ -*-
0002  *  Copyright (C) 2003-2005 Thiago Macieira <thiago@kde.org>
0003  *
0004  *
0005  *  Permission is hereby granted, free of charge, to any person obtaining
0006  *  a copy of this software and associated documentation files (the
0007  *  "Software"), to deal in the Software without restriction, including
0008  *  without limitation the rights to use, copy, modify, merge, publish,
0009  *  distribute, sublicense, and/or sell copies of the Software, and to
0010  *  permit persons to whom the Software is furnished to do so, subject to
0011  *  the following conditions:
0012  *
0013  *  The above copyright notice and this permission notice shall be included
0014  *  in all copies or substantial portions of the Software.
0015  *
0016  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0017  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0018  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0019  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0020  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0021  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0022  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0023  */
0024 
0025 #include "k3resolver.h"
0026 #include "k3resolver_p.h"
0027 
0028 #include <config-network.h>
0029 
0030 // System includes
0031 #include <sys/types.h>
0032 #include <sys/socket.h>
0033 #include <sys/param.h>
0034 #include <errno.h>
0035 #include <netdb.h>
0036 #include <time.h>
0037 #include <arpa/inet.h>
0038 #include <netinet/in.h>
0039 #include <stdlib.h>
0040 #include <unistd.h>
0041 
0042 // Qt includes
0043 #include <QCoreApplication>
0044 #include <QPointer>
0045 #include <QSet>
0046 #include <QUrl>
0047 
0048 #include <QStringList>
0049 #include <QSharedData>
0050 #include <QElapsedTimer>
0051 
0052 // KDE
0053 #include <klocalizedstring.h>
0054 
0055 // Us
0056 
0057 #ifdef NEED_MUTEX
0058 #ifdef __GNUC__
0059 #warning "mutex"
0060 #endif
0061 QMutex getXXbyYYmutex;
0062 #endif
0063 
0064 #ifdef __OpenBSD__
0065 #define USE_OPENBSD 1
0066 #endif
0067 
0068 using namespace KNetwork;
0069 using namespace KNetwork::Internal;
0070 
0071 /////////////////////////////////////////////
0072 // class KResolverEntry
0073 
0074 class KNetwork::KResolverEntryPrivate: public QSharedData
0075 {
0076 public:
0077     KSocketAddress addr;
0078     int socktype;
0079     int protocol;
0080     QString canonName;
0081     QByteArray encodedName;
0082 
0083     inline KResolverEntryPrivate() :
0084         socktype(0), protocol(0)
0085     { }
0086 };
0087 
0088 // default constructor
0089 KResolverEntry::KResolverEntry() :
0090     d(nullptr)
0091 {
0092 }
0093 
0094 // constructor with stuff
0095 KResolverEntry::KResolverEntry(const KSocketAddress &addr, int socktype, int protocol,
0096                                const QString &canonName, const QByteArray &encodedName) :
0097     d(new KResolverEntryPrivate)
0098 {
0099     d->addr = addr;
0100     d->socktype = socktype;
0101     d->protocol = protocol;
0102     d->canonName = canonName;
0103     d->encodedName = encodedName;
0104 }
0105 
0106 // constructor with even more stuff
0107 KResolverEntry::KResolverEntry(const struct sockaddr *sa, quint16 salen, int socktype,
0108                                int protocol, const QString &canonName,
0109                                const QByteArray &encodedName) :
0110     d(new KResolverEntryPrivate)
0111 {
0112     d->addr = KSocketAddress(sa, salen);
0113     d->socktype = socktype;
0114     d->protocol = protocol;
0115     d->canonName = canonName;
0116     d->encodedName = encodedName;
0117 }
0118 
0119 // copy constructor
0120 KResolverEntry::KResolverEntry(const KResolverEntry &that) :
0121     d(nullptr)
0122 {
0123     *this = that;
0124 }
0125 
0126 // destructor
0127 KResolverEntry::~KResolverEntry()
0128 {
0129 }
0130 
0131 // returns the socket address
0132 KSocketAddress KResolverEntry::address() const
0133 {
0134     return d->addr;
0135 }
0136 
0137 // returns the length
0138 quint16 KResolverEntry::length() const
0139 {
0140     return d->addr.length();
0141 }
0142 
0143 // returns the family
0144 int KResolverEntry::family() const
0145 {
0146     return d->addr.family();
0147 }
0148 
0149 // returns the canonical name
0150 QString KResolverEntry::canonicalName() const
0151 {
0152     return d->canonName;
0153 }
0154 
0155 // returns the encoded name
0156 QByteArray KResolverEntry::encodedName() const
0157 {
0158     return d->encodedName;
0159 }
0160 
0161 // returns the socket type
0162 int KResolverEntry::socketType() const
0163 {
0164     return d->socktype;
0165 }
0166 
0167 // returns the protocol
0168 int KResolverEntry::protocol() const
0169 {
0170     return d->protocol;
0171 }
0172 
0173 // assignment operator
0174 KResolverEntry &KResolverEntry::operator= (const KResolverEntry &that)
0175 {
0176     d = that.d;
0177     return *this;
0178 }
0179 
0180 /////////////////////////////////////////////
0181 // class KResolverResults
0182 
0183 class KNetwork::KResolverResultsPrivate: public QSharedData
0184 {
0185 public:
0186     QString node, service;
0187     int errorcode, syserror;
0188 
0189     KResolverResultsPrivate() :
0190         errorcode(0), syserror(0)
0191     { }
0192 };
0193 
0194 // default constructor
0195 KResolverResults::KResolverResults()
0196     : d(new KResolverResultsPrivate)
0197 {
0198 }
0199 
0200 // copy constructor
0201 KResolverResults::KResolverResults(const KResolverResults &other)
0202     : QList<KResolverEntry>(other), d(new KResolverResultsPrivate)
0203 {
0204     d = other.d;
0205 }
0206 
0207 // destructor
0208 KResolverResults::~KResolverResults()
0209 {
0210 }
0211 
0212 // assignment operator
0213 KResolverResults &
0214 KResolverResults::operator= (const KResolverResults &other)
0215 {
0216     // copy over the other data
0217     d = other.d;
0218 
0219     // now let QList do the rest of the work
0220     QList<KResolverEntry>::operator =(other);
0221 
0222     return *this;
0223 }
0224 
0225 // gets the error code
0226 int KResolverResults::error() const
0227 {
0228     return d->errorcode;
0229 }
0230 
0231 // gets the system errno
0232 int KResolverResults::systemError() const
0233 {
0234     return d->syserror;
0235 }
0236 
0237 // sets the error codes
0238 void KResolverResults::setError(int errorcode, int systemerror)
0239 {
0240     d->errorcode = errorcode;
0241     d->syserror = systemerror;
0242 }
0243 
0244 // gets the hostname
0245 QString KResolverResults::nodeName() const
0246 {
0247     return d->node;
0248 }
0249 
0250 // gets the service name
0251 QString KResolverResults::serviceName() const
0252 {
0253     return d->service;
0254 }
0255 
0256 // sets the address
0257 void KResolverResults::setAddress(const QString &node,
0258                                   const QString &service)
0259 {
0260     d->node = node;
0261     d->service = service;
0262 }
0263 
0264 void KResolverResults::virtual_hook(int, void *)
0265 {
0266     /*BASE::virtual_hook( id, data );*/
0267 }
0268 
0269 ///////////////////////
0270 // class KResolver
0271 
0272 // default constructor
0273 KResolver::KResolver(QObject *parent)
0274     : QObject(parent), d(new KResolverPrivate(this))
0275 {
0276 }
0277 
0278 // constructor with host and service
0279 KResolver::KResolver(const QString &nodename, const QString &servicename,
0280                      QObject *parent)
0281     : QObject(parent), d(new KResolverPrivate(this, nodename, servicename))
0282 {
0283 }
0284 
0285 // destructor
0286 KResolver::~KResolver()
0287 {
0288     cancel(false);
0289     delete d;
0290 }
0291 
0292 // get the status
0293 int KResolver::status() const
0294 {
0295     return d->status;
0296 }
0297 
0298 // get the error code
0299 int KResolver::error() const
0300 {
0301     return d->errorcode;
0302 }
0303 
0304 // get the errno
0305 int KResolver::systemError() const
0306 {
0307     return d->syserror;
0308 }
0309 
0310 QString KResolver::errorString() const
0311 {
0312     return errorString(error(), systemError());
0313 }
0314 
0315 // are we running?
0316 bool KResolver::isRunning() const
0317 {
0318     return d->status > 0 && d->status < Success;
0319 }
0320 
0321 // get the hostname
0322 QString KResolver::nodeName() const
0323 {
0324     return d->input.node;
0325 }
0326 
0327 // get the service
0328 QString KResolver::serviceName() const
0329 {
0330     return d->input.service;
0331 }
0332 
0333 // sets the hostname
0334 void KResolver::setNodeName(const QString &nodename)
0335 {
0336     // don't touch those values if we're working!
0337     if (!isRunning()) {
0338         d->input.node = nodename;
0339         d->status = Idle;
0340         d->results.setAddress(nodename, d->input.service);
0341     }
0342 }
0343 
0344 // sets the service
0345 void KResolver::setServiceName(const QString &service)
0346 {
0347     // don't change if running
0348     if (!isRunning()) {
0349         d->input.service = service;
0350         d->status = Idle;
0351         d->results.setAddress(d->input.node, service);
0352     }
0353 }
0354 
0355 // sets the address
0356 void KResolver::setAddress(const QString &nodename, const QString &service)
0357 {
0358     setNodeName(nodename);
0359     setServiceName(service);
0360 }
0361 
0362 // get the flags
0363 int KResolver::flags() const
0364 {
0365     return d->input.flags;
0366 }
0367 
0368 // sets the flags
0369 int KResolver::setFlags(int flags)
0370 {
0371     int oldflags = d->input.flags;
0372     if (!isRunning()) {
0373         d->input.flags = flags;
0374         d->status = Idle;
0375     }
0376     return oldflags;
0377 }
0378 
0379 // sets the family mask
0380 void KResolver::setFamily(int families)
0381 {
0382     if (!isRunning()) {
0383         d->input.familyMask = families;
0384         d->status = Idle;
0385     }
0386 }
0387 
0388 // sets the socket type
0389 void KResolver::setSocketType(int type)
0390 {
0391     if (!isRunning()) {
0392         d->input.socktype = type;
0393         d->status = Idle;
0394     }
0395 }
0396 
0397 // sets the protocol
0398 void KResolver::setProtocol(int protonum, const char *name)
0399 {
0400     if (isRunning()) {
0401         return;    // can't change now
0402     }
0403 
0404     // we copy the given protocol name. If it isn't an empty string
0405     // and the protocol number was 0, we will look it up in /etc/protocols
0406     // we also leave the error reporting to the actual lookup routines, in
0407     // case the given protocol name doesn't exist
0408 
0409     d->input.protocolName = name;
0410     if (protonum == 0 && name != nullptr && *name != '\0') {
0411         // must look up the protocol number
0412         d->input.protocol = KResolver::protocolNumber(name);
0413     } else {
0414         d->input.protocol = protonum;
0415     }
0416     d->status = Idle;
0417 }
0418 
0419 bool KResolver::start()
0420 {
0421     if (!isRunning()) {
0422         d->results.clear();
0423 
0424         // is there anything to be queued?
0425         if (d->input.node.isEmpty() && d->input.service.isEmpty()) {
0426             d->status = KResolver::Success;
0427             emitFinished();
0428         } else {
0429             KResolverManager::manager()->enqueue(this, nullptr);
0430         }
0431     }
0432 
0433     return true;
0434 }
0435 
0436 bool KResolver::wait(int msec)
0437 {
0438     if (!isRunning()) {
0439         emitFinished();
0440         return true;
0441     }
0442 
0443     QMutexLocker locker(&d->mutex);
0444 
0445     if (!isRunning()) {
0446         // it was running and no longer is?
0447         // That means the manager has finished its processing and has posted
0448         // an event for the signal to be emitted already. This means the signal
0449         // will be emitted twice!
0450 
0451         emitFinished();
0452         return true;
0453     } else {
0454         QElapsedTimer t;
0455         t.start();
0456 
0457         while (!msec || t.elapsed() < msec) {
0458             // wait on the manager to broadcast completion
0459             d->waiting = true;
0460             if (msec) {
0461                 KResolverManager::manager()->notifyWaiters.wait(&d->mutex, msec - t.elapsed());
0462             } else {
0463                 KResolverManager::manager()->notifyWaiters.wait(&d->mutex);
0464             }
0465 
0466             // the manager has processed
0467             // see if this object is done
0468             if (!isRunning()) {
0469                 // it's done
0470                 d->waiting = false;
0471                 emitFinished();
0472                 return true;
0473             }
0474         }
0475 
0476         // if we've got here, we've timed out
0477         d->waiting = false;
0478         return false;
0479     }
0480 }
0481 
0482 void KResolver::cancel(bool emitSignal)
0483 {
0484     KResolverManager::manager()->dequeue(this);
0485     if (emitSignal) {
0486         emitFinished();
0487     }
0488 }
0489 
0490 KResolverResults
0491 KResolver::results() const
0492 {
0493     if (!isRunning()) {
0494         return d->results;
0495     }
0496 
0497     // return a dummy, empty result
0498     KResolverResults r;
0499     r.setAddress(d->input.node, d->input.service);
0500     r.setError(d->errorcode, d->syserror);
0501     return r;
0502 }
0503 
0504 bool KResolver::event(QEvent *e)
0505 {
0506     if (static_cast<int>(e->type()) == KResolverManager::ResolutionCompleted) {
0507         emitFinished();
0508         return true;
0509     }
0510 
0511     return QObject::event(e);
0512 }
0513 
0514 void KResolver::emitFinished()
0515 {
0516     if (isRunning()) {
0517         d->status = KResolver::Success;
0518     }
0519 
0520     QPointer<QObject> p = this; // guard against deletion
0521 
0522     emit finished(d->results);
0523 
0524     if (p && d->deleteWhenDone) {
0525         deleteLater();    // in QObject
0526     }
0527 }
0528 
0529 QString KResolver::errorString(int errorcode, int syserror)
0530 {
0531     // no i18n now...
0532     static const char messages[] = {
0533         I18N_NOOP("no error")"\0"   // NoError
0534         I18N_NOOP("requested family not supported for this host name")"\0" // AddrFamily
0535         I18N_NOOP("temporary failure in name resolution")"\0"   // TryAgain
0536         I18N_NOOP("non-recoverable failure in name resolution")"\0" // NonRecoverable
0537         I18N_NOOP("invalid flags")"\0"      // BadFlags
0538         I18N_NOOP("memory allocation failure")"\0"  // Memory
0539         I18N_NOOP("name or service not known")"\0"  // NoName
0540         I18N_NOOP("requested family not supported")"\0" // UnsupportedFamily
0541         I18N_NOOP("requested service not supported for this socket type")"\0" // UnsupportedService
0542         I18N_NOOP("requested socket type not supported")"\0"    // UnsupportedSocketType
0543         I18N_NOOP("unknown error")"\0"          // UnknownError
0544         I18N_NOOP2("1: the i18n'ed system error code, from errno",
0545         "system error: %1")"\0"       // SystemError
0546         "\0"
0547     };
0548     // index table generated by generate_string_table.pl
0549     static const int messages_indices[] = {
0550         0,    9,   59,   96,  139,  153,  179,  205,
0551         236,  289,  325,    0
0552     };
0553 
0554     // handle the special value
0555     if (errorcode == Canceled) {
0556         return i18n("request was canceled");
0557     }
0558 
0559     Q_ASSERT(int(SystemError) <= -(int)(sizeof(messages_indices) / sizeof(messages_indices[0])));
0560     if (errorcode > 0 || errorcode < SystemError) {
0561         return QString();
0562     }
0563 
0564     QString msg = i18n(messages + messages_indices[-errorcode]);
0565     if (errorcode == SystemError) {
0566         msg = msg.arg(QString::fromLocal8Bit(strerror(syserror)));
0567     }
0568 
0569     return msg;
0570 }
0571 
0572 KResolverResults
0573 KResolver::resolve(const QString &host, const QString &service, int flags,
0574                    int families)
0575 {
0576     KResolver qres(host, service, QCoreApplication::instance());
0577     qres.setObjectName(QString::fromLatin1("synchronous KResolver"));
0578     qres.setFlags(flags);
0579     qres.setFamily(families);
0580     qres.start();
0581     qres.wait();
0582     return qres.results();
0583 }
0584 
0585 bool KResolver::resolveAsync(QObject *userObj, const char *userSlot,
0586                              const QString &host, const QString &service,
0587                              int flags, int families)
0588 {
0589     KResolver *qres = new KResolver(host, service, QCoreApplication::instance());
0590     QObject::connect(qres, SIGNAL(finished(KNetwork::KResolverResults)),
0591                      userObj, userSlot);
0592     qres->setObjectName(QString::fromLatin1("asynchronous KResolver"));
0593     qres->setFlags(flags);
0594     qres->setFamily(families);
0595     qres->d->deleteWhenDone = true; // this is the only difference from the example code
0596     return qres->start();
0597 }
0598 
0599 QList<QByteArray> KResolver::protocolName(int protonum)
0600 {
0601     struct protoent *pe;
0602 #if !HAVE_GETPROTOBYNAME_R
0603     QMutexLocker locker(&getXXbyYYmutex);
0604 
0605     pe = getprotobynumber(protonum);
0606 
0607 #else
0608 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API
0609     struct protoent protobuf;
0610     struct protoent_data pdata;
0611     ::memset(&pdata, 0, sizeof pdata);
0612 
0613     if (getprotobynumber_r(protonum, &protobuf, &pdata) == 0) {
0614         pe = &protobuf;
0615     } else {
0616         pe = 0;
0617     }
0618 
0619 # else
0620     size_t buflen = 1024;
0621     struct protoent protobuf;
0622     char *buf;
0623     do {
0624         buf = new char[buflen];
0625 #  ifdef Q_OS_SOLARIS // Solaris uses a 4 argument getprotobynumber_r which returns struct *protoent or NULL
0626         if ((pe = getprotobynumber_r(protonum, &protobuf, buf, buflen)) && (errno == ERANGE))
0627 #  else
0628         if (getprotobynumber_r(protonum, &protobuf, buf, buflen, &pe) == ERANGE)
0629 #  endif
0630         {
0631             buflen += 1024;
0632             delete [] buf;
0633         } else {
0634             break;
0635         }
0636     } while (pe == nullptr);
0637 # endif
0638 #endif
0639 
0640     // Do common processing
0641     QList<QByteArray> lst;
0642     if (pe != nullptr) {
0643         lst.append(pe->p_name);
0644         for (char **p = pe->p_aliases; *p; p++) {
0645             lst.append(*p);
0646         }
0647     }
0648 
0649 #if HAVE_GETPROTOBYNAME_R
0650 # ifndef USE_OPENBSD
0651     delete [] buf;
0652 # endif
0653 #endif
0654 
0655     return lst;
0656 }
0657 
0658 QList<QByteArray> KResolver::protocolName(const char *protoname)
0659 {
0660     struct protoent *pe = nullptr;
0661 #if !HAVE_GETPROTOBYNAME_R
0662     QMutexLocker locker(&getXXbyYYmutex);
0663 
0664     pe = getprotobyname(protoname);
0665 
0666 #else
0667 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API
0668     struct protoent protobuf;
0669     struct protoent_data pdata;
0670     ::memset(&pdata, 0, sizeof pdata);
0671 
0672     if (getprotobyname_r(protoname, &protobuf, &pdata) == 0) {
0673         pe = &protobuf;
0674     } else {
0675         pe = 0;
0676     }
0677 # else
0678     size_t buflen = 1024;
0679     struct protoent protobuf;
0680     char *buf;
0681     do {
0682         buf = new char[buflen];
0683 #  ifdef Q_OS_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL
0684         if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE))
0685 #  else
0686         if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE)
0687 #  endif
0688         {
0689             pe = nullptr;
0690             buflen += 1024;
0691             delete [] buf;
0692         } else {
0693             break;
0694         }
0695     } while (pe == nullptr);
0696 # endif
0697 #endif
0698 
0699     // Do common processing
0700     QList<QByteArray> lst;
0701     if (pe != nullptr) {
0702         lst.append(pe->p_name);
0703         for (char **p = pe->p_aliases; *p; p++) {
0704             lst.append(*p);
0705         }
0706     }
0707 
0708 #if HAVE_GETPROTOBYNAME_R
0709 # ifndef USE_OPENBSD
0710     delete [] buf;
0711 # endif
0712 #endif
0713 
0714     return lst;
0715 }
0716 
0717 int KResolver::protocolNumber(const char *protoname)
0718 {
0719     struct protoent *pe = nullptr;
0720 #if !HAVE_GETPROTOBYNAME_R
0721     QMutexLocker locker(&getXXbyYYmutex);
0722 
0723     pe = getprotobyname(protoname);
0724 
0725 #else
0726 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API
0727     struct protoent protobuf;
0728     struct protoent_data pdata;
0729     ::memset(&pdata, 0, sizeof pdata);
0730 
0731     if (getprotobyname_r(protoname, &protobuf, &pdata) == 0) {
0732         pe = &protobuf;
0733     } else {
0734         pe = 0;
0735     }
0736 
0737 # else
0738     size_t buflen = 1024;
0739     struct protoent protobuf;
0740     char *buf;
0741     do {
0742         buf = new char[buflen];
0743 #  ifdef Q_OS_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL
0744         if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE))
0745 #  else
0746         if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE)
0747 #  endif
0748         {
0749             pe = nullptr;
0750             buflen += 1024;
0751             delete [] buf;
0752         } else {
0753             break;
0754         }
0755     } while (pe == nullptr);
0756 # endif
0757 #endif
0758 
0759     // Do common processing
0760     int protonum = -1;
0761     if (pe != nullptr) {
0762         protonum = pe->p_proto;
0763     }
0764 
0765 #if HAVE_GETPROTOBYNAME_R
0766 # ifndef USE_OPENBSD
0767     delete [] buf;
0768 # endif
0769 #endif
0770 
0771     return protonum;
0772 }
0773 
0774 int KResolver::servicePort(const char *servname, const char *protoname)
0775 {
0776     struct servent *se = nullptr;
0777 #if !HAVE_GETSERVBYNAME_R
0778     QMutexLocker locker(&getXXbyYYmutex);
0779 
0780     se = getservbyname(servname, protoname);
0781 
0782 #else
0783 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API
0784     struct servent servbuf;
0785     struct servent_data sdata;
0786     ::memset(&sdata, 0, sizeof sdata);
0787     if (getservbyname_r(servname, protoname, &servbuf, &sdata) == 0) {
0788         se = &servbuf;
0789     } else {
0790         se = 0;
0791     }
0792 
0793 # else
0794     size_t buflen = 1024;
0795     struct servent servbuf;
0796     char *buf;
0797     do {
0798         buf = new char[buflen];
0799 #  ifdef Q_OS_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL
0800         if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
0801 #  else
0802         if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE)
0803 #  endif
0804         {
0805             se = nullptr;
0806             buflen += 1024;
0807             delete [] buf;
0808         } else {
0809             break;
0810         }
0811     } while (se == nullptr);
0812 # endif
0813 #endif
0814 
0815     // Do common processing
0816     int servport = -1;
0817     if (se != nullptr) {
0818         servport = ntohs(se->s_port);
0819     }
0820 
0821 #if HAVE_GETSERVBYNAME_R
0822 # ifndef USE_OPENBSD
0823     delete [] buf;
0824 # endif
0825 #endif
0826 
0827     return servport;
0828 }
0829 
0830 QList<QByteArray> KResolver::serviceName(const char *servname, const char *protoname)
0831 {
0832     struct servent *se = nullptr;
0833 #if !HAVE_GETSERVBYNAME_R
0834     QMutexLocker locker(&getXXbyYYmutex);
0835 
0836     se = getservbyname(servname, protoname);
0837 
0838 #else
0839 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API
0840     struct servent servbuf;
0841     struct servent_data sdata;
0842     ::memset(&sdata, 0, sizeof sdata);
0843     if (getservbyname_r(servname, protoname, &servbuf, &sdata) == 0) {
0844         se = &servbuf;
0845     } else {
0846         se = 0;
0847     }
0848 
0849 # else
0850     size_t buflen = 1024;
0851     struct servent servbuf;
0852     char *buf;
0853     do {
0854         buf = new char[buflen];
0855 #  ifdef Q_OS_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL
0856         if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
0857 #  else
0858         if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE)
0859 #  endif
0860         {
0861             se = nullptr;
0862             buflen += 1024;
0863             delete [] buf;
0864         } else {
0865             break;
0866         }
0867     } while (se == nullptr);
0868 # endif
0869 #endif
0870 
0871     // Do common processing
0872     QList<QByteArray> lst;
0873     if (se != nullptr) {
0874         lst.append(se->s_name);
0875         for (char **p = se->s_aliases; *p; p++) {
0876             lst.append(*p);
0877         }
0878     }
0879 
0880 #if HAVE_GETSERVBYNAME_R
0881 # ifndef USE_OPENBSD
0882     delete [] buf;
0883 # endif
0884 #endif
0885 
0886     return lst;
0887 }
0888 
0889 QList<QByteArray> KResolver::serviceName(int port, const char *protoname)
0890 {
0891     struct servent *se = nullptr;
0892 #if !HAVE_GETSERVBYPORT_R
0893     QMutexLocker locker(&getXXbyYYmutex);
0894 
0895     se = getservbyport(port, protoname);
0896 
0897 #else
0898 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API
0899     struct servent servbuf;
0900     struct servent_data sdata;
0901     ::memset(&sdata, 0, sizeof sdata);
0902     if (getservbyport_r(port, protoname, &servbuf, &sdata) == 0) {
0903         se = &servbuf;
0904     } else {
0905         se = 0;
0906     }
0907 
0908 # else
0909     size_t buflen = 1024;
0910     struct servent servbuf;
0911     char *buf;
0912     do {
0913         buf = new char[buflen];
0914 #  ifdef Q_OS_SOLARIS // Solaris uses a 5 argument getservbyport_r which returns struct *servent or NULL
0915         if ((se = getservbyport_r(port, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
0916 #  else
0917         if (getservbyport_r(port, protoname, &servbuf, buf, buflen, &se) == ERANGE)
0918 #  endif
0919         {
0920             se = nullptr;
0921             buflen += 1024;
0922             delete [] buf;
0923         } else {
0924             break;
0925         }
0926     } while (se == nullptr);
0927 # endif
0928 #endif
0929 
0930     // Do common processing
0931     QList<QByteArray> lst;
0932     if (se != nullptr) {
0933         lst.append(se->s_name);
0934         for (char **p = se->s_aliases; *p; p++) {
0935             lst.append(*p);
0936         }
0937     }
0938 
0939 #if HAVE_GETSERVBYPORT_R
0940 # ifndef USE_OPENBSD
0941     delete [] buf;
0942 # endif
0943 #endif
0944 
0945     return lst;
0946 }
0947 
0948 QString KResolver::localHostName()
0949 {
0950     QByteArray name;
0951     int len;
0952 
0953 #ifdef MAXHOSTNAMELEN
0954     len = MAXHOSTNAMELEN;
0955 #else
0956     len = 256;
0957 #endif
0958 
0959     while (true) {
0960         name.resize(len);
0961 
0962         if (gethostname(name.data(), len) == 0) {
0963             // Call succeeded, but it's not guaranteed to be NUL-terminated
0964             // Fortunately, QByteArray is always NUL-terminated
0965 
0966             // Note that some systems return success even if they did truncation
0967             break;
0968         }
0969 
0970         // Call failed
0971         if (errno == ENAMETOOLONG || errno == EINVAL) {
0972             len += 256;
0973         } else {
0974             // Oops! Unknown error!
0975             name.clear();
0976         }
0977     }
0978 
0979     if (name.isEmpty()) {
0980         return QLatin1String("localhost");
0981     }
0982 
0983     if (name.indexOf('.') == -1) {
0984         // not fully qualified
0985         // must resolve
0986         KResolverResults results = resolve(QString::fromLocal8Bit(name), QString::fromLatin1("0"), CanonName);
0987         if (results.isEmpty())
0988             // cannot find a valid hostname!
0989         {
0990             return QLatin1String("localhost");
0991         } else {
0992             return results.first().canonicalName();
0993         }
0994     }
0995 
0996     return domainToUnicode(name);
0997 }
0998 
0999 static void KResolver_initIdnDomains()
1000 {
1001     static bool init = false;
1002     if (!init) {
1003         QByteArray kde_use_idn = qgetenv("KDE_USE_IDN");
1004         if (!kde_use_idn.isEmpty()) {
1005             QUrl::setIdnWhitelist(QString::fromLatin1(kde_use_idn).toLower().split(QLatin1Char(':')));
1006         }
1007         init = true;
1008     }
1009 }
1010 
1011 // implement the ToAscii function, as described by IDN documents
1012 QByteArray KResolver::domainToAscii(const QString &unicodeDomain)
1013 {
1014     KResolver_initIdnDomains();
1015     return QUrl::toAce(unicodeDomain);
1016 }
1017 
1018 QString KResolver::domainToUnicode(const QByteArray &asciiDomain)
1019 {
1020     return domainToUnicode(QString::fromLatin1(asciiDomain));
1021 }
1022 
1023 // implement the ToUnicode function, as described by IDN documents
1024 QString KResolver::domainToUnicode(const QString &asciiDomain)
1025 {
1026     if (asciiDomain.isEmpty()) {
1027         return asciiDomain;
1028     }
1029     KResolver_initIdnDomains();
1030     return QUrl::fromAce(asciiDomain.toLatin1());
1031 }
1032 
1033 QString KResolver::normalizeDomain(const QString &domain)
1034 {
1035     return domainToUnicode(domainToAscii(domain));
1036 }
1037 
1038 void KResolver::virtual_hook(int, void *)
1039 {
1040     /*BASE::virtual_hook( id, data );*/
1041 }
1042 
1043 // here follows IDN functions
1044 // all IDN functions conform to the following documents:
1045 //  RFC 3454 - Preparation of Internationalized Strings
1046 //  RFC 3490 - Internationalizing Domain Names in Applications (IDNA)
1047 //  RFC 3491 - Nameprep: A Stringprep Profile for
1048 //                Internationalized Domain Names (IDN
1049 //  RFC 3492 - Punycode: A Bootstring encoding of Unicode
1050 //          for Internationalized Domain Names in Applications (IDNA)
1051 
1052 #include "moc_k3resolver.cpp"