File indexing completed on 2023-09-24 04:04:38
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"