KDECore
k3resolver.cpp
Go to the documentation of this file.
00001 /* -*- C++ -*- 00002 * Copyright (C) 2003-2005 Thiago Macieira <thiago@kde.org> 00003 * 00004 * 00005 * Permission is hereby granted, free of charge, to any person obtaining 00006 * a copy of this software and associated documentation files (the 00007 * "Software"), to deal in the Software without restriction, including 00008 * without limitation the rights to use, copy, modify, merge, publish, 00009 * distribute, sublicense, and/or sell copies of the Software, and to 00010 * permit persons to whom the Software is furnished to do so, subject to 00011 * the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be included 00014 * in all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 00020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00025 #include "k3resolver.h" 00026 #include "k3resolver_p.h" 00027 00028 #include <config.h> 00029 #include <config-network.h> 00030 00031 // System includes 00032 #include <sys/types.h> 00033 #include <sys/socket.h> 00034 #include <sys/param.h> 00035 #include <errno.h> 00036 #include <netdb.h> 00037 #include <time.h> 00038 #include <arpa/inet.h> 00039 #include <netinet/in.h> 00040 #include <stdlib.h> 00041 #include <unistd.h> 00042 00043 // Qt includes 00044 #include <QCoreApplication> 00045 #include <QPointer> 00046 #include <QSet> 00047 00048 #include <QStringList> 00049 #include <QSharedData> 00050 #include <QTime> 00051 #include <QTimer> 00052 00053 // KDE 00054 #include <klocale.h> 00055 #include <kurl.h> 00056 00057 // Us 00058 #include "k3socketaddress.h" 00059 00060 #ifdef NEED_MUTEX 00061 #ifdef __GNUC__ 00062 #warning "mutex" 00063 #endif 00064 QMutex getXXbyYYmutex; 00065 #endif 00066 00067 #ifdef __OpenBSD__ 00068 #define USE_OPENBSD 1 00069 #endif 00070 00071 using namespace KNetwork; 00072 using namespace KNetwork::Internal; 00073 00075 // class KResolverEntry 00076 00077 class KNetwork::KResolverEntryPrivate: public QSharedData 00078 { 00079 public: 00080 KSocketAddress addr; 00081 int socktype; 00082 int protocol; 00083 QString canonName; 00084 QByteArray encodedName; 00085 00086 inline KResolverEntryPrivate() : 00087 socktype(0), protocol(0) 00088 { } 00089 }; 00090 00091 // default constructor 00092 KResolverEntry::KResolverEntry() : 00093 d(0L) 00094 { 00095 } 00096 00097 // constructor with stuff 00098 KResolverEntry::KResolverEntry(const KSocketAddress& addr, int socktype, int protocol, 00099 const QString& canonName, const QByteArray& encodedName) : 00100 d(new KResolverEntryPrivate) 00101 { 00102 d->addr = addr; 00103 d->socktype = socktype; 00104 d->protocol = protocol; 00105 d->canonName = canonName; 00106 d->encodedName = encodedName; 00107 } 00108 00109 // constructor with even more stuff 00110 KResolverEntry::KResolverEntry(const struct sockaddr* sa, quint16 salen, int socktype, 00111 int protocol, const QString& canonName, 00112 const QByteArray& encodedName) : 00113 d(new KResolverEntryPrivate) 00114 { 00115 d->addr = KSocketAddress(sa, salen); 00116 d->socktype = socktype; 00117 d->protocol = protocol; 00118 d->canonName = canonName; 00119 d->encodedName = encodedName; 00120 } 00121 00122 // copy constructor 00123 KResolverEntry::KResolverEntry(const KResolverEntry& that) : 00124 d(0L) 00125 { 00126 *this = that; 00127 } 00128 00129 // destructor 00130 KResolverEntry::~KResolverEntry() 00131 { 00132 } 00133 00134 // returns the socket address 00135 KSocketAddress KResolverEntry::address() const 00136 { 00137 return d->addr; 00138 } 00139 00140 // returns the length 00141 quint16 KResolverEntry::length() const 00142 { 00143 return d->addr.length(); 00144 } 00145 00146 // returns the family 00147 int KResolverEntry::family() const 00148 { 00149 return d->addr.family(); 00150 } 00151 00152 // returns the canonical name 00153 QString KResolverEntry::canonicalName() const 00154 { 00155 return d->canonName; 00156 } 00157 00158 // returns the encoded name 00159 QByteArray KResolverEntry::encodedName() const 00160 { 00161 return d->encodedName; 00162 } 00163 00164 // returns the socket type 00165 int KResolverEntry::socketType() const 00166 { 00167 return d->socktype; 00168 } 00169 00170 // returns the protocol 00171 int KResolverEntry::protocol() const 00172 { 00173 return d->protocol; 00174 } 00175 00176 // assignment operator 00177 KResolverEntry& KResolverEntry::operator= (const KResolverEntry& that) 00178 { 00179 d = that.d; 00180 return *this; 00181 } 00182 00184 // class KResolverResults 00185 00186 class KNetwork::KResolverResultsPrivate: public QSharedData 00187 { 00188 public: 00189 QString node, service; 00190 int errorcode, syserror; 00191 00192 KResolverResultsPrivate() : 00193 errorcode(0), syserror(0) 00194 { } 00195 }; 00196 00197 // default constructor 00198 KResolverResults::KResolverResults() 00199 : d(new KResolverResultsPrivate) 00200 { 00201 } 00202 00203 // copy constructor 00204 KResolverResults::KResolverResults(const KResolverResults& other) 00205 : QList<KResolverEntry>(other), d(new KResolverResultsPrivate) 00206 { 00207 d = other.d; 00208 } 00209 00210 // destructor 00211 KResolverResults::~KResolverResults() 00212 { 00213 } 00214 00215 // assignment operator 00216 KResolverResults& 00217 KResolverResults::operator= (const KResolverResults& other) 00218 { 00219 // copy over the other data 00220 d = other.d; 00221 00222 // now let QList do the rest of the work 00223 QList<KResolverEntry>::operator =(other); 00224 00225 return *this; 00226 } 00227 00228 // gets the error code 00229 int KResolverResults::error() const 00230 { 00231 return d->errorcode; 00232 } 00233 00234 // gets the system errno 00235 int KResolverResults::systemError() const 00236 { 00237 return d->syserror; 00238 } 00239 00240 // sets the error codes 00241 void KResolverResults::setError(int errorcode, int systemerror) 00242 { 00243 d->errorcode = errorcode; 00244 d->syserror = systemerror; 00245 } 00246 00247 // gets the hostname 00248 QString KResolverResults::nodeName() const 00249 { 00250 return d->node; 00251 } 00252 00253 // gets the service name 00254 QString KResolverResults::serviceName() const 00255 { 00256 return d->service; 00257 } 00258 00259 // sets the address 00260 void KResolverResults::setAddress(const QString& node, 00261 const QString& service) 00262 { 00263 d->node = node; 00264 d->service = service; 00265 } 00266 00267 void KResolverResults::virtual_hook( int, void* ) 00268 { /*BASE::virtual_hook( id, data );*/ } 00269 00270 00272 // class KResolver 00273 00274 // default constructor 00275 KResolver::KResolver(QObject *parent) 00276 : QObject(parent), d(new KResolverPrivate(this)) 00277 { 00278 } 00279 00280 // constructor with host and service 00281 KResolver::KResolver(const QString& nodename, const QString& servicename, 00282 QObject *parent) 00283 : QObject(parent), d(new KResolverPrivate(this, nodename, servicename)) 00284 { 00285 } 00286 00287 // destructor 00288 KResolver::~KResolver() 00289 { 00290 cancel(false); 00291 delete d; 00292 } 00293 00294 // get the status 00295 int KResolver::status() const 00296 { 00297 return d->status; 00298 } 00299 00300 // get the error code 00301 int KResolver::error() const 00302 { 00303 return d->errorcode; 00304 } 00305 00306 // get the errno 00307 int KResolver::systemError() const 00308 { 00309 return d->syserror; 00310 } 00311 00312 QString KResolver::errorString() const 00313 { 00314 return errorString(error(), systemError()); 00315 } 00316 00317 // are we running? 00318 bool KResolver::isRunning() const 00319 { 00320 return d->status > 0 && d->status < Success; 00321 } 00322 00323 // get the hostname 00324 QString KResolver::nodeName() const 00325 { 00326 return d->input.node; 00327 } 00328 00329 // get the service 00330 QString KResolver::serviceName() const 00331 { 00332 return d->input.service; 00333 } 00334 00335 // sets the hostname 00336 void KResolver::setNodeName(const QString& nodename) 00337 { 00338 // don't touch those values if we're working! 00339 if (!isRunning()) 00340 { 00341 d->input.node = nodename; 00342 d->status = Idle; 00343 d->results.setAddress(nodename, d->input.service); 00344 } 00345 } 00346 00347 // sets the service 00348 void KResolver::setServiceName(const QString& service) 00349 { 00350 // don't change if running 00351 if (!isRunning()) 00352 { 00353 d->input.service = service; 00354 d->status = Idle; 00355 d->results.setAddress(d->input.node, service); 00356 } 00357 } 00358 00359 // sets the address 00360 void KResolver::setAddress(const QString& nodename, const QString& service) 00361 { 00362 setNodeName(nodename); 00363 setServiceName(service); 00364 } 00365 00366 // get the flags 00367 int KResolver::flags() const 00368 { 00369 return d->input.flags; 00370 } 00371 00372 // sets the flags 00373 int KResolver::setFlags(int flags) 00374 { 00375 int oldflags = d->input.flags; 00376 if (!isRunning()) 00377 { 00378 d->input.flags = flags; 00379 d->status = Idle; 00380 } 00381 return oldflags; 00382 } 00383 00384 // sets the family mask 00385 void KResolver::setFamily(int families) 00386 { 00387 if (!isRunning()) 00388 { 00389 d->input.familyMask = families; 00390 d->status = Idle; 00391 } 00392 } 00393 00394 // sets the socket type 00395 void KResolver::setSocketType(int type) 00396 { 00397 if (!isRunning()) 00398 { 00399 d->input.socktype = type; 00400 d->status = Idle; 00401 } 00402 } 00403 00404 // sets the protocol 00405 void KResolver::setProtocol(int protonum, const char *name) 00406 { 00407 if (isRunning()) 00408 return; // can't change now 00409 00410 // we copy the given protocol name. If it isn't an empty string 00411 // and the protocol number was 0, we will look it up in /etc/protocols 00412 // we also leave the error reporting to the actual lookup routines, in 00413 // case the given protocol name doesn't exist 00414 00415 d->input.protocolName = name; 00416 if (protonum == 0 && name != 0L && *name != '\0') 00417 { 00418 // must look up the protocol number 00419 d->input.protocol = KResolver::protocolNumber(name); 00420 } 00421 else 00422 d->input.protocol = protonum; 00423 d->status = Idle; 00424 } 00425 00426 bool KResolver::start() 00427 { 00428 if (!isRunning()) 00429 { 00430 d->results.empty(); 00431 00432 // is there anything to be queued? 00433 if (d->input.node.isEmpty() && d->input.service.isEmpty()) 00434 { 00435 d->status = KResolver::Success; 00436 emitFinished(); 00437 } 00438 else 00439 KResolverManager::manager()->enqueue(this, 0L); 00440 } 00441 00442 return true; 00443 } 00444 00445 bool KResolver::wait(int msec) 00446 { 00447 if (!isRunning()) 00448 { 00449 emitFinished(); 00450 return true; 00451 } 00452 00453 QMutexLocker locker(&d->mutex); 00454 00455 if (!isRunning()) 00456 { 00457 // it was running and no longer is? 00458 // That means the manager has finished its processing and has posted 00459 // an event for the signal to be emitted already. This means the signal 00460 // will be emitted twice! 00461 00462 emitFinished(); 00463 return true; 00464 } 00465 else 00466 { 00467 QTime t; 00468 t.start(); 00469 00470 while (!msec || t.elapsed() < msec) 00471 { 00472 // wait on the manager to broadcast completion 00473 d->waiting = true; 00474 if (msec) 00475 KResolverManager::manager()->notifyWaiters.wait(&d->mutex, msec - t.elapsed()); 00476 else 00477 KResolverManager::manager()->notifyWaiters.wait(&d->mutex); 00478 00479 // the manager has processed 00480 // see if this object is done 00481 if (!isRunning()) 00482 { 00483 // it's done 00484 d->waiting = false; 00485 emitFinished(); 00486 return true; 00487 } 00488 } 00489 00490 // if we've got here, we've timed out 00491 d->waiting = false; 00492 return false; 00493 } 00494 } 00495 00496 void KResolver::cancel(bool emitSignal) 00497 { 00498 KResolverManager::manager()->dequeue(this); 00499 if (emitSignal) 00500 emitFinished(); 00501 } 00502 00503 KResolverResults 00504 KResolver::results() const 00505 { 00506 if (!isRunning()) 00507 return d->results; 00508 00509 // return a dummy, empty result 00510 KResolverResults r; 00511 r.setAddress(d->input.node, d->input.service); 00512 r.setError(d->errorcode, d->syserror); 00513 return r; 00514 } 00515 00516 bool KResolver::event(QEvent* e) 00517 { 00518 if (static_cast<int>(e->type()) == KResolverManager::ResolutionCompleted) 00519 { 00520 emitFinished(); 00521 return true; 00522 } 00523 00524 return false; 00525 } 00526 00527 void KResolver::emitFinished() 00528 { 00529 if (isRunning()) 00530 d->status = KResolver::Success; 00531 00532 QPointer<QObject> p = this; // guard against deletion 00533 00534 emit finished(d->results); 00535 00536 if (p && d->deleteWhenDone) 00537 deleteLater(); // in QObject 00538 } 00539 00540 QString KResolver::errorString(int errorcode, int syserror) 00541 { 00542 // no i18n now... 00543 static const char messages[] = 00544 { 00545 I18N_NOOP("no error")"\0" // NoError 00546 I18N_NOOP("requested family not supported for this host name")"\0" // AddrFamily 00547 I18N_NOOP("temporary failure in name resolution")"\0" // TryAgain 00548 I18N_NOOP("non-recoverable failure in name resolution")"\0" // NonRecoverable 00549 I18N_NOOP("invalid flags")"\0" // BadFlags 00550 I18N_NOOP("memory allocation failure")"\0" // Memory 00551 I18N_NOOP("name or service not known")"\0" // NoName 00552 I18N_NOOP("requested family not supported")"\0" // UnsupportedFamily 00553 I18N_NOOP("requested service not supported for this socket type")"\0" // UnsupportedService 00554 I18N_NOOP("requested socket type not supported")"\0" // UnsupportedSocketType 00555 I18N_NOOP("unknown error")"\0" // UnknownError 00556 I18N_NOOP2("1: the i18n'ed system error code, from errno", 00557 "system error: %1")"\0" // SystemError 00558 "\0" 00559 }; 00560 // index table generated by generate_string_table.pl 00561 static const int messages_indices[] = { 00562 0, 9, 59, 96, 139, 153, 179, 205, 00563 236, 289, 325, 0 00564 }; 00565 00566 // handle the special value 00567 if (errorcode == Canceled) 00568 return i18n("request was canceled"); 00569 00570 Q_ASSERT(int(SystemError) <= -(int)(sizeof(messages_indices)/sizeof(messages_indices[0]))); 00571 if (errorcode > 0 || errorcode < SystemError) 00572 return QString(); 00573 00574 QString msg = i18n(messages + messages_indices[-errorcode]); 00575 if (errorcode == SystemError) 00576 msg.arg(QString::fromLocal8Bit(strerror(syserror))); 00577 00578 return msg; 00579 } 00580 00581 KResolverResults 00582 KResolver::resolve(const QString& host, const QString& service, int flags, 00583 int families) 00584 { 00585 KResolver qres(host, service, QCoreApplication::instance()); 00586 qres.setObjectName(QString::fromLatin1("synchronous KResolver")); 00587 qres.setFlags(flags); 00588 qres.setFamily(families); 00589 qres.start(); 00590 qres.wait(); 00591 return qres.results(); 00592 } 00593 00594 bool KResolver::resolveAsync(QObject* userObj, const char *userSlot, 00595 const QString& host, const QString& service, 00596 int flags, int families) 00597 { 00598 KResolver* qres = new KResolver(host, service, QCoreApplication::instance()); 00599 QObject::connect(qres, SIGNAL(finished(const KNetwork::KResolverResults&)), 00600 userObj, userSlot); 00601 qres->setObjectName(QString::fromLatin1("asynchronous KResolver")); 00602 qres->setFlags(flags); 00603 qres->setFamily(families); 00604 qres->d->deleteWhenDone = true; // this is the only difference from the example code 00605 return qres->start(); 00606 } 00607 00608 QList<QByteArray> KResolver::protocolName(int protonum) 00609 { 00610 struct protoent *pe; 00611 #ifndef HAVE_GETPROTOBYNAME_R 00612 QMutexLocker locker(&getXXbyYYmutex); 00613 00614 pe = getprotobynumber(protonum); 00615 00616 #else 00617 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API 00618 struct protoent protobuf; 00619 struct protoent_data pdata; 00620 ::memset(&pdata, 0, sizeof pdata); 00621 00622 if (getprotobynumber_r(protonum, &protobuf, &pdata) == 0) 00623 pe = &protobuf; 00624 else 00625 pe = 0; 00626 00627 # else 00628 size_t buflen = 1024; 00629 struct protoent protobuf; 00630 char *buf; 00631 do 00632 { 00633 buf = new char[buflen]; 00634 # ifdef Q_OS_SOLARIS // Solaris uses a 4 argument getprotobynumber_r which returns struct *protoent or NULL 00635 if ((pe = getprotobynumber_r(protonum, &protobuf, buf, buflen)) && (errno == ERANGE)) 00636 # else 00637 if (getprotobynumber_r(protonum, &protobuf, buf, buflen, &pe) == ERANGE) 00638 # endif 00639 { 00640 buflen += 1024; 00641 delete [] buf; 00642 } 00643 else 00644 break; 00645 } 00646 while (pe == 0L); 00647 # endif 00648 #endif 00649 00650 // Do common processing 00651 QList<QByteArray> lst; 00652 if (pe != NULL) 00653 { 00654 lst.append(pe->p_name); 00655 for (char **p = pe->p_aliases; *p; p++) 00656 lst.append(*p); 00657 } 00658 00659 #ifdef HAVE_GETPROTOBYNAME_R 00660 # ifndef USE_OPENBSD 00661 delete [] buf; 00662 # endif 00663 #endif 00664 00665 return lst; 00666 } 00667 00668 QList<QByteArray> KResolver::protocolName(const char *protoname) 00669 { 00670 struct protoent *pe = 0L; 00671 #ifndef HAVE_GETPROTOBYNAME_R 00672 QMutexLocker locker(&getXXbyYYmutex); 00673 00674 pe = getprotobyname(protoname); 00675 00676 #else 00677 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API 00678 struct protoent protobuf; 00679 struct protoent_data pdata; 00680 ::memset(&pdata, 0, sizeof pdata); 00681 00682 if (getprotobyname_r(protoname, &protobuf, &pdata) == 0) 00683 pe = &protobuf; 00684 else 00685 pe = 0; 00686 # else 00687 size_t buflen = 1024; 00688 struct protoent protobuf; 00689 char *buf; 00690 do 00691 { 00692 buf = new char[buflen]; 00693 # ifdef Q_OS_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL 00694 if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE)) 00695 # else 00696 if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE) 00697 # endif 00698 { 00699 pe = 0L; 00700 buflen += 1024; 00701 delete [] buf; 00702 } 00703 else 00704 break; 00705 } 00706 while (pe == 0L); 00707 # endif 00708 #endif 00709 00710 // Do common processing 00711 QList<QByteArray> lst; 00712 if (pe != NULL) 00713 { 00714 lst.append(pe->p_name); 00715 for (char **p = pe->p_aliases; *p; p++) 00716 lst.append(*p); 00717 } 00718 00719 #ifdef HAVE_GETPROTOBYNAME_R 00720 # ifndef USE_OPENBSD 00721 delete [] buf; 00722 # endif 00723 #endif 00724 00725 return lst; 00726 } 00727 00728 int KResolver::protocolNumber(const char *protoname) 00729 { 00730 struct protoent *pe = 0L; 00731 #ifndef HAVE_GETPROTOBYNAME_R 00732 QMutexLocker locker(&getXXbyYYmutex); 00733 00734 pe = getprotobyname(protoname); 00735 00736 #else 00737 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API 00738 struct protoent protobuf; 00739 struct protoent_data pdata; 00740 ::memset(&pdata, 0, sizeof pdata); 00741 00742 if (getprotobyname_r(protoname, &protobuf, &pdata) == 0) 00743 pe = &protobuf; 00744 else 00745 pe = 0; 00746 00747 # else 00748 size_t buflen = 1024; 00749 struct protoent protobuf; 00750 char *buf; 00751 do 00752 { 00753 buf = new char[buflen]; 00754 # ifdef Q_OS_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL 00755 if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE)) 00756 # else 00757 if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE) 00758 # endif 00759 { 00760 pe = 0L; 00761 buflen += 1024; 00762 delete [] buf; 00763 } 00764 else 00765 break; 00766 } 00767 while (pe == 0L); 00768 # endif 00769 #endif 00770 00771 // Do common processing 00772 int protonum = -1; 00773 if (pe != NULL) 00774 protonum = pe->p_proto; 00775 00776 #ifdef HAVE_GETPROTOBYNAME_R 00777 # ifndef USE_OPENBSD 00778 delete [] buf; 00779 # endif 00780 #endif 00781 00782 return protonum; 00783 } 00784 00785 int KResolver::servicePort(const char *servname, const char *protoname) 00786 { 00787 struct servent *se = 0L; 00788 #ifndef HAVE_GETSERVBYNAME_R 00789 QMutexLocker locker(&getXXbyYYmutex); 00790 00791 se = getservbyname(servname, protoname); 00792 00793 #else 00794 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API 00795 struct servent servbuf; 00796 struct servent_data sdata; 00797 ::memset(&sdata, 0, sizeof sdata); 00798 if (getservbyname_r(servname, protoname, &servbuf, &sdata) == 0) 00799 se = &servbuf; 00800 else 00801 se = 0; 00802 00803 # else 00804 size_t buflen = 1024; 00805 struct servent servbuf; 00806 char *buf; 00807 do 00808 { 00809 buf = new char[buflen]; 00810 # ifdef Q_OS_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL 00811 if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE)) 00812 # else 00813 if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00814 # endif 00815 { 00816 se = 0L; 00817 buflen += 1024; 00818 delete [] buf; 00819 } 00820 else 00821 break; 00822 } 00823 while (se == 0L); 00824 # endif 00825 #endif 00826 00827 // Do common processing 00828 int servport = -1; 00829 if (se != NULL) 00830 servport = ntohs(se->s_port); 00831 00832 #ifdef HAVE_GETSERVBYNAME_R 00833 # ifndef USE_OPENBSD 00834 delete [] buf; 00835 # endif 00836 #endif 00837 00838 return servport; 00839 } 00840 00841 QList<QByteArray> KResolver::serviceName(const char* servname, const char *protoname) 00842 { 00843 struct servent *se = 0L; 00844 #ifndef HAVE_GETSERVBYNAME_R 00845 QMutexLocker locker(&getXXbyYYmutex); 00846 00847 se = getservbyname(servname, protoname); 00848 00849 #else 00850 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API 00851 struct servent servbuf; 00852 struct servent_data sdata; 00853 ::memset(&sdata, 0, sizeof sdata); 00854 if (getservbyname_r(servname, protoname, &servbuf, &sdata) == 0) 00855 se = &servbuf; 00856 else 00857 se = 0; 00858 00859 # else 00860 size_t buflen = 1024; 00861 struct servent servbuf; 00862 char *buf; 00863 do 00864 { 00865 buf = new char[buflen]; 00866 # ifdef Q_OS_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL 00867 if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE)) 00868 # else 00869 if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00870 # endif 00871 { 00872 se = 0L; 00873 buflen += 1024; 00874 delete [] buf; 00875 } 00876 else 00877 break; 00878 } 00879 while (se == 0L); 00880 # endif 00881 #endif 00882 00883 // Do common processing 00884 QList<QByteArray> lst; 00885 if (se != NULL) 00886 { 00887 lst.append(se->s_name); 00888 for (char **p = se->s_aliases; *p; p++) 00889 lst.append(*p); 00890 } 00891 00892 #ifdef HAVE_GETSERVBYNAME_R 00893 # ifndef USE_OPENBSD 00894 delete [] buf; 00895 # endif 00896 #endif 00897 00898 return lst; 00899 } 00900 00901 QList<QByteArray> KResolver::serviceName(int port, const char *protoname) 00902 { 00903 struct servent *se = 0L; 00904 #ifndef HAVE_GETSERVBYPORT_R 00905 QMutexLocker locker(&getXXbyYYmutex); 00906 00907 se = getservbyport(port, protoname); 00908 00909 #else 00910 # ifdef USE_OPENBSD // OpenBSD uses an HP/IBM/DEC API 00911 struct servent servbuf; 00912 struct servent_data sdata; 00913 ::memset(&sdata, 0, sizeof sdata); 00914 if (getservbyport_r(port, protoname, &servbuf, &sdata) == 0) 00915 se = &servbuf; 00916 else 00917 se = 0; 00918 00919 # else 00920 size_t buflen = 1024; 00921 struct servent servbuf; 00922 char *buf; 00923 do 00924 { 00925 buf = new char[buflen]; 00926 # ifdef Q_OS_SOLARIS // Solaris uses a 5 argument getservbyport_r which returns struct *servent or NULL 00927 if ((se = getservbyport_r(port, protoname, &servbuf, buf, buflen)) && (errno == ERANGE)) 00928 # else 00929 if (getservbyport_r(port, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00930 # endif 00931 { 00932 se = 0L; 00933 buflen += 1024; 00934 delete [] buf; 00935 } 00936 else 00937 break; 00938 } 00939 while (se == 0L); 00940 # endif 00941 #endif 00942 00943 // Do common processing 00944 QList<QByteArray> lst; 00945 if (se != NULL) 00946 { 00947 lst.append(se->s_name); 00948 for (char **p = se->s_aliases; *p; p++) 00949 lst.append(*p); 00950 } 00951 00952 #ifdef HAVE_GETSERVBYPORT_R 00953 # ifndef USE_OPENBSD 00954 delete [] buf; 00955 # endif 00956 #endif 00957 00958 return lst; 00959 } 00960 00961 QString KResolver::localHostName() 00962 { 00963 QByteArray name; 00964 int len; 00965 00966 #ifdef MAXHOSTNAMELEN 00967 len = MAXHOSTNAMELEN; 00968 #else 00969 len = 256; 00970 #endif 00971 00972 while (true) 00973 { 00974 name.resize(len); 00975 00976 if (gethostname(name.data(), len) == 0) 00977 { 00978 // Call succeeded, but it's not guaranteed to be NUL-terminated 00979 // Fortunately, QByteArray is always NUL-terminated 00980 00981 // Note that some systems return success even if they did truncation 00982 break; 00983 } 00984 00985 // Call failed 00986 if (errno == ENAMETOOLONG || errno == EINVAL) 00987 len += 256; 00988 else 00989 { 00990 // Oops! Unknown error! 00991 name.clear(); 00992 } 00993 } 00994 00995 if (name.isEmpty()) 00996 return QLatin1String("localhost"); 00997 00998 if (name.indexOf('.') == -1) 00999 { 01000 // not fully qualified 01001 // must resolve 01002 KResolverResults results = resolve(QString::fromLocal8Bit(name), QString::fromLatin1("0"), CanonName); 01003 if (results.isEmpty()) 01004 // cannot find a valid hostname! 01005 return QLatin1String("localhost"); 01006 else 01007 return results.first().canonicalName(); 01008 } 01009 01010 return domainToUnicode(name); 01011 } 01012 01013 static void KResolver_initIdnDomains() 01014 { 01015 static bool init = false; 01016 if (!init) 01017 { 01018 QByteArray kde_use_idn = qgetenv("KDE_USE_IDN"); 01019 if (!kde_use_idn.isEmpty()) 01020 KUrl::setIdnWhitelist(QString::fromLatin1(kde_use_idn).toLower().split(QLatin1Char(':'))); 01021 init = true; 01022 } 01023 } 01024 01025 // implement the ToAscii function, as described by IDN documents 01026 QByteArray KResolver::domainToAscii(const QString& unicodeDomain) 01027 { 01028 KResolver_initIdnDomains(); 01029 return KUrl::toAce(unicodeDomain); 01030 } 01031 01032 QString KResolver::domainToUnicode(const QByteArray& asciiDomain) 01033 { 01034 return domainToUnicode(QString::fromLatin1(asciiDomain)); 01035 } 01036 01037 // implement the ToUnicode function, as described by IDN documents 01038 QString KResolver::domainToUnicode(const QString& asciiDomain) 01039 { 01040 if (asciiDomain.isEmpty()) 01041 return asciiDomain; 01042 KResolver_initIdnDomains(); 01043 return KUrl::fromAce(asciiDomain.toLatin1()); 01044 } 01045 01046 QString KResolver::normalizeDomain(const QString& domain) 01047 { 01048 return domainToUnicode(domainToAscii(domain)); 01049 } 01050 01051 void KResolver::virtual_hook( int, void* ) 01052 { /*BASE::virtual_hook( id, data );*/ } 01053 01054 // here follows IDN functions 01055 // all IDN functions conform to the following documents: 01056 // RFC 3454 - Preparation of Internationalized Strings 01057 // RFC 3490 - Internationalizing Domain Names in Applications (IDNA) 01058 // RFC 3491 - Nameprep: A Stringprep Profile for 01059 // Internationalized Domain Names (IDN 01060 // RFC 3492 - Punycode: A Bootstring encoding of Unicode 01061 // for Internationalized Domain Names in Applications (IDNA) 01062 01063 #include "k3resolver.moc"
KDE 4.6 API Reference