kresolver.cpp
00001 /* -*- C++ -*- 00002 * Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net> 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 "config.h" 00026 00027 // System includes 00028 #include <sys/types.h> 00029 #include <sys/socket.h> 00030 #include <sys/param.h> 00031 #include <errno.h> 00032 #include <netdb.h> 00033 #include <time.h> 00034 #include <arpa/inet.h> 00035 #include <netinet/in.h> 00036 #include <stdlib.h> 00037 #include <unistd.h> 00038 00039 // Qt includes 00040 #include <qapplication.h> 00041 #include <qstring.h> 00042 #include <qcstring.h> 00043 #include <qstrlist.h> 00044 #include <qstringlist.h> 00045 #include <qshared.h> 00046 #include <qdatetime.h> 00047 #include <qtimer.h> 00048 #include <qmutex.h> 00049 #include <qguardedptr.h> 00050 00051 // IDN 00052 #ifdef HAVE_IDNA_H 00053 # include <idna.h> 00054 #endif 00055 00056 // KDE 00057 #include <klocale.h> 00058 00059 // Us 00060 #include "kresolver.h" 00061 #include "kresolver_p.h" 00062 #include "ksocketaddress.h" 00063 00064 #ifdef NEED_MUTEX 00065 #warning "mutex" 00066 QMutex getXXbyYYmutex; 00067 #endif 00068 00069 using namespace KNetwork; 00070 using namespace KNetwork::Internal; 00071 00073 // class KResolverEntry 00074 00075 class KNetwork::KResolverEntryPrivate: public QShared 00076 { 00077 public: 00078 KSocketAddress addr; 00079 int socktype; 00080 int protocol; 00081 QString canonName; 00082 QCString encodedName; 00083 00084 inline KResolverEntryPrivate() : 00085 socktype(0), protocol(0) 00086 { } 00087 }; 00088 00089 // default constructor 00090 KResolverEntry::KResolverEntry() : 00091 d(0L) 00092 { 00093 } 00094 00095 // constructor with stuff 00096 KResolverEntry::KResolverEntry(const KSocketAddress& addr, int socktype, int protocol, 00097 const QString& canonName, const QCString& encodedName) : 00098 d(new KResolverEntryPrivate) 00099 { 00100 d->addr = addr; 00101 d->socktype = socktype; 00102 d->protocol = protocol; 00103 d->canonName = canonName; 00104 d->encodedName = encodedName; 00105 } 00106 00107 // constructor with even more stuff 00108 KResolverEntry::KResolverEntry(const struct sockaddr* sa, Q_UINT16 salen, int socktype, 00109 int protocol, const QString& canonName, 00110 const QCString& encodedName) : 00111 d(new KResolverEntryPrivate) 00112 { 00113 d->addr = KSocketAddress(sa, salen); 00114 d->socktype = socktype; 00115 d->protocol = protocol; 00116 d->canonName = canonName; 00117 d->encodedName = encodedName; 00118 } 00119 00120 // copy constructor 00121 KResolverEntry::KResolverEntry(const KResolverEntry& that) : 00122 d(0L) 00123 { 00124 *this = that; 00125 } 00126 00127 // destructor 00128 KResolverEntry::~KResolverEntry() 00129 { 00130 if (d == 0L) 00131 return; 00132 00133 if (d->deref()) 00134 delete d; 00135 } 00136 00137 // returns the socket address 00138 KSocketAddress KResolverEntry::address() const 00139 { 00140 return d ? d->addr : KSocketAddress(); 00141 } 00142 00143 // returns the length 00144 Q_UINT16 KResolverEntry::length() const 00145 { 00146 return d ? d->addr.length() : 0; 00147 } 00148 00149 // returns the family 00150 int KResolverEntry::family() const 00151 { 00152 return d ? d->addr.family() : AF_UNSPEC; 00153 } 00154 00155 // returns the canonical name 00156 QString KResolverEntry::canonicalName() const 00157 { 00158 return d ? d->canonName : QString::null; 00159 } 00160 00161 // returns the encoded name 00162 QCString KResolverEntry::encodedName() const 00163 { 00164 return d ? d->encodedName : QCString(); 00165 } 00166 00167 // returns the socket type 00168 int KResolverEntry::socketType() const 00169 { 00170 return d ? d->socktype : 0; 00171 } 00172 00173 // returns the protocol 00174 int KResolverEntry::protocol() const 00175 { 00176 return d ? d->protocol : 0; 00177 } 00178 00179 // assignment operator 00180 KResolverEntry& KResolverEntry::operator= (const KResolverEntry& that) 00181 { 00182 // copy the data 00183 if (that.d) 00184 that.d->ref(); 00185 00186 if (d && d->deref()) 00187 delete d; 00188 00189 d = that.d; 00190 return *this; 00191 } 00192 00194 // class KResolverResults 00195 00196 class KNetwork::KResolverResultsPrivate 00197 { 00198 public: 00199 QString node, service; 00200 int errorcode, syserror; 00201 00202 KResolverResultsPrivate() : 00203 errorcode(0), syserror(0) 00204 { } 00205 }; 00206 00207 // default constructor 00208 KResolverResults::KResolverResults() 00209 : d(new KResolverResultsPrivate) 00210 { 00211 } 00212 00213 // copy constructor 00214 KResolverResults::KResolverResults(const KResolverResults& other) 00215 : QValueList<KResolverEntry>(other), d(new KResolverResultsPrivate) 00216 { 00217 *d = *other.d; 00218 } 00219 00220 // destructor 00221 KResolverResults::~KResolverResults() 00222 { 00223 delete d; 00224 } 00225 00226 // assignment operator 00227 KResolverResults& 00228 KResolverResults::operator= (const KResolverResults& other) 00229 { 00230 if (this == &other) 00231 return *this; 00232 00233 // copy over the other data 00234 *d = *other.d; 00235 00236 // now let QValueList do the rest of the work 00237 QValueList<KResolverEntry>::operator =(other); 00238 00239 return *this; 00240 } 00241 00242 // gets the error code 00243 int KResolverResults::error() const 00244 { 00245 return d->errorcode; 00246 } 00247 00248 // gets the system errno 00249 int KResolverResults::systemError() const 00250 { 00251 return d->syserror; 00252 } 00253 00254 // sets the error codes 00255 void KResolverResults::setError(int errorcode, int systemerror) 00256 { 00257 d->errorcode = errorcode; 00258 d->syserror = systemerror; 00259 } 00260 00261 // gets the hostname 00262 QString KResolverResults::nodeName() const 00263 { 00264 return d->node; 00265 } 00266 00267 // gets the service name 00268 QString KResolverResults::serviceName() const 00269 { 00270 return d->service; 00271 } 00272 00273 // sets the address 00274 void KResolverResults::setAddress(const QString& node, 00275 const QString& service) 00276 { 00277 d->node = node; 00278 d->service = service; 00279 } 00280 00281 void KResolverResults::virtual_hook( int, void* ) 00282 { /*BASE::virtual_hook( id, data );*/ } 00283 00284 00286 // class KResolver 00287 00288 QStringList *KResolver::idnDomains = 0; 00289 00290 00291 // default constructor 00292 KResolver::KResolver(QObject *parent, const char *name) 00293 : QObject(parent, name), d(new KResolverPrivate(this)) 00294 { 00295 } 00296 00297 // constructor with host and service 00298 KResolver::KResolver(const QString& nodename, const QString& servicename, 00299 QObject *parent, const char *name) 00300 : QObject(parent, name), d(new KResolverPrivate(this, nodename, servicename)) 00301 { 00302 } 00303 00304 // destructor 00305 KResolver::~KResolver() 00306 { 00307 cancel(false); 00308 delete d; 00309 } 00310 00311 // get the status 00312 int KResolver::status() const 00313 { 00314 return d->status; 00315 } 00316 00317 // get the error code 00318 int KResolver::error() const 00319 { 00320 return d->errorcode; 00321 } 00322 00323 // get the errno 00324 int KResolver::systemError() const 00325 { 00326 return d->syserror; 00327 } 00328 00329 // are we running? 00330 bool KResolver::isRunning() const 00331 { 00332 return d->status > 0 && d->status < Success; 00333 } 00334 00335 // get the hostname 00336 QString KResolver::nodeName() const 00337 { 00338 return d->input.node; 00339 } 00340 00341 // get the service 00342 QString KResolver::serviceName() const 00343 { 00344 return d->input.service; 00345 } 00346 00347 // sets the hostname 00348 void KResolver::setNodeName(const QString& nodename) 00349 { 00350 // don't touch those values if we're working! 00351 if (!isRunning()) 00352 { 00353 d->input.node = nodename; 00354 d->status = Idle; 00355 d->results.setAddress(nodename, d->input.service); 00356 } 00357 } 00358 00359 // sets the service 00360 void KResolver::setServiceName(const QString& service) 00361 { 00362 // don't change if running 00363 if (!isRunning()) 00364 { 00365 d->input.service = service; 00366 d->status = Idle; 00367 d->results.setAddress(d->input.node, service); 00368 } 00369 } 00370 00371 // sets the address 00372 void KResolver::setAddress(const QString& nodename, const QString& service) 00373 { 00374 setNodeName(nodename); 00375 setServiceName(service); 00376 } 00377 00378 // get the flags 00379 int KResolver::flags() const 00380 { 00381 return d->input.flags; 00382 } 00383 00384 // sets the flags 00385 int KResolver::setFlags(int flags) 00386 { 00387 int oldflags = d->input.flags; 00388 if (!isRunning()) 00389 { 00390 d->input.flags = flags; 00391 d->status = Idle; 00392 } 00393 return oldflags; 00394 } 00395 00396 // sets the family mask 00397 void KResolver::setFamily(int families) 00398 { 00399 if (!isRunning()) 00400 { 00401 d->input.familyMask = families; 00402 d->status = Idle; 00403 } 00404 } 00405 00406 // sets the socket type 00407 void KResolver::setSocketType(int type) 00408 { 00409 if (!isRunning()) 00410 { 00411 d->input.socktype = type; 00412 d->status = Idle; 00413 } 00414 } 00415 00416 // sets the protocol 00417 void KResolver::setProtocol(int protonum, const char *name) 00418 { 00419 if (isRunning()) 00420 return; // can't change now 00421 00422 // we copy the given protocol name. If it isn't an empty string 00423 // and the protocol number was 0, we will look it up in /etc/protocols 00424 // we also leave the error reporting to the actual lookup routines, in 00425 // case the given protocol name doesn't exist 00426 00427 d->input.protocolName = name; 00428 if (protonum == 0 && name != 0L && *name != '\0') 00429 { 00430 // must look up the protocol number 00431 d->input.protocol = KResolver::protocolNumber(name); 00432 } 00433 else 00434 d->input.protocol = protonum; 00435 d->status = Idle; 00436 } 00437 00438 bool KResolver::start() 00439 { 00440 if (!isRunning()) 00441 { 00442 d->results.empty(); 00443 00444 // is there anything to be queued? 00445 if (d->input.node.isEmpty() && d->input.service.isEmpty()) 00446 { 00447 d->status = KResolver::Success; 00448 emitFinished(); 00449 } 00450 else 00451 KResolverManager::manager()->enqueue(this, 0L); 00452 } 00453 00454 return true; 00455 } 00456 00457 bool KResolver::wait(int msec) 00458 { 00459 if (!isRunning()) 00460 { 00461 emitFinished(); 00462 return true; 00463 } 00464 00465 QMutexLocker locker(&d->mutex); 00466 00467 if (!isRunning()) 00468 { 00469 // it was running and no longer is? 00470 // That means the manager has finished its processing and has posted 00471 // an event for the signal to be emitted already. This means the signal 00472 // will be emitted twice! 00473 00474 emitFinished(); 00475 return true; 00476 } 00477 else 00478 { 00479 QTime t; 00480 t.start(); 00481 00482 while (!msec || t.elapsed() < msec) 00483 { 00484 // wait on the manager to broadcast completion 00485 d->waiting = true; 00486 if (msec) 00487 KResolverManager::manager()->notifyWaiters.wait(&d->mutex, msec - t.elapsed()); 00488 else 00489 KResolverManager::manager()->notifyWaiters.wait(&d->mutex); 00490 00491 // the manager has processed 00492 // see if this object is done 00493 if (!isRunning()) 00494 { 00495 // it's done 00496 d->waiting = false; 00497 emitFinished(); 00498 return true; 00499 } 00500 } 00501 00502 // if we've got here, we've timed out 00503 d->waiting = false; 00504 return false; 00505 } 00506 } 00507 00508 void KResolver::cancel(bool emitSignal) 00509 { 00510 KResolverManager::manager()->dequeue(this); 00511 if (emitSignal) 00512 emitFinished(); 00513 } 00514 00515 KResolverResults 00516 KResolver::results() const 00517 { 00518 if (!isRunning()) 00519 return d->results; 00520 00521 // return a dummy, empty result 00522 KResolverResults r; 00523 r.setAddress(d->input.node, d->input.service); 00524 r.setError(d->errorcode, d->syserror); 00525 return r; 00526 } 00527 00528 bool KResolver::event(QEvent* e) 00529 { 00530 if (static_cast<int>(e->type()) == KResolverManager::ResolutionCompleted) 00531 { 00532 emitFinished(); 00533 return true; 00534 } 00535 00536 return false; 00537 } 00538 00539 void KResolver::emitFinished() 00540 { 00541 if (isRunning()) 00542 d->status = KResolver::Success; 00543 00544 QGuardedPtr<QObject> p = this; // guard against deletion 00545 00546 emit finished(d->results); 00547 00548 if (p && d->deleteWhenDone) 00549 deleteLater(); // in QObject 00550 } 00551 00552 QString KResolver::errorString(int errorcode, int syserror) 00553 { 00554 // no i18n now... 00555 static const char * const messages[] = 00556 { 00557 I18N_NOOP("no error"), // NoError 00558 I18N_NOOP("requested family not supported for this host name"), // AddrFamily 00559 I18N_NOOP("temporary failure in name resolution"), // TryAgain 00560 I18N_NOOP("non-recoverable failure in name resolution"), // NonRecoverable 00561 I18N_NOOP("invalid flags"), // BadFlags 00562 I18N_NOOP("memory allocation failure"), // Memory 00563 I18N_NOOP("name or service not known"), // NoName 00564 I18N_NOOP("requested family not supported"), // UnsupportedFamily 00565 I18N_NOOP("requested service not supported for this socket type"), // UnsupportedService 00566 I18N_NOOP("requested socket type not supported"), // UnsupportedSocketType 00567 I18N_NOOP("unknown error"), // UnknownError 00568 I18N_NOOP2("1: the i18n'ed system error code, from errno", 00569 "system error: %1") // SystemError 00570 }; 00571 00572 // handle the special value 00573 if (errorcode == Canceled) 00574 return i18n("request was canceled"); 00575 00576 if (errorcode > 0 || errorcode < SystemError) 00577 return QString::null; 00578 00579 QString msg = i18n(messages[-errorcode]); 00580 if (errorcode == SystemError) 00581 msg.arg(QString::fromLocal8Bit(strerror(syserror))); 00582 00583 return msg; 00584 } 00585 00586 KResolverResults 00587 KResolver::resolve(const QString& host, const QString& service, int flags, 00588 int families) 00589 { 00590 KResolver qres(host, service, qApp, "synchronous KResolver"); 00591 qres.setFlags(flags); 00592 qres.setFamily(families); 00593 qres.start(); 00594 qres.wait(); 00595 return qres.results(); 00596 } 00597 00598 bool KResolver::resolveAsync(QObject* userObj, const char *userSlot, 00599 const QString& host, const QString& service, 00600 int flags, int families) 00601 { 00602 KResolver* qres = new KResolver(host, service, qApp, "asynchronous KResolver"); 00603 QObject::connect(qres, SIGNAL(finished(KResolverResults)), userObj, userSlot); 00604 qres->setFlags(flags); 00605 qres->setFamily(families); 00606 qres->d->deleteWhenDone = true; // this is the only difference from the example code 00607 return qres->start(); 00608 } 00609 00610 QStrList KResolver::protocolName(int protonum) 00611 { 00612 struct protoent *pe = 0L; 00613 #ifndef HAVE_GETPROTOBYNAME_R 00614 QMutexLocker locker(&getXXbyYYmutex); 00615 00616 pe = getprotobynumber(protonum); 00617 00618 #else 00619 size_t buflen = 1024; 00620 struct protoent protobuf; 00621 char *buf; 00622 do 00623 { 00624 buf = new char[buflen]; 00625 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobynumber_r which returns struct *protoent or NULL 00626 if ((pe = getprotobynumber_r(protonum, &protobuf, buf, buflen)) && (errno == ERANGE)) 00627 # else 00628 if (getprotobynumber_r(protonum, &protobuf, buf, buflen, &pe) == ERANGE) 00629 # endif 00630 { 00631 pe = 0L; 00632 buflen += 1024; 00633 delete [] buf; 00634 } 00635 else 00636 break; 00637 } 00638 while (pe == 0L); 00639 #endif 00640 00641 // Do common processing 00642 QStrList lst(true); // use deep copies 00643 if (pe != NULL) 00644 { 00645 lst.append(pe->p_name); 00646 for (char **p = pe->p_aliases; *p; p++) 00647 lst.append(*p); 00648 } 00649 00650 #ifdef HAVE_GETPROTOBYNAME_R 00651 delete [] buf; 00652 #endif 00653 00654 return lst; 00655 } 00656 00657 QStrList KResolver::protocolName(const char *protoname) 00658 { 00659 struct protoent *pe = 0L; 00660 #ifndef HAVE_GETPROTOBYNAME_R 00661 QMutexLocker locker(&getXXbyYYmutex); 00662 00663 pe = getprotobyname(protoname); 00664 00665 #else 00666 size_t buflen = 1024; 00667 struct protoent protobuf; 00668 char *buf; 00669 do 00670 { 00671 buf = new char[buflen]; 00672 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL 00673 if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE)) 00674 # else 00675 if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE) 00676 # endif 00677 { 00678 pe = 0L; 00679 buflen += 1024; 00680 delete [] buf; 00681 } 00682 else 00683 break; 00684 } 00685 while (pe == 0L); 00686 #endif 00687 00688 // Do common processing 00689 QStrList lst(true); // use deep copies 00690 if (pe != NULL) 00691 { 00692 lst.append(pe->p_name); 00693 for (char **p = pe->p_aliases; *p; p++) 00694 lst.append(*p); 00695 } 00696 00697 #ifdef HAVE_GETPROTOBYNAME_R 00698 delete [] buf; 00699 #endif 00700 00701 return lst; 00702 } 00703 00704 int KResolver::protocolNumber(const char *protoname) 00705 { 00706 struct protoent *pe = 0L; 00707 #ifndef HAVE_GETPROTOBYNAME_R 00708 QMutexLocker locker(&getXXbyYYmutex); 00709 00710 pe = getprotobyname(protoname); 00711 00712 #else 00713 size_t buflen = 1024; 00714 struct protoent protobuf; 00715 char *buf; 00716 do 00717 { 00718 buf = new char[buflen]; 00719 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL 00720 if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE)) 00721 # else 00722 if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE) 00723 # endif 00724 { 00725 pe = 0L; 00726 buflen += 1024; 00727 delete [] buf; 00728 } 00729 else 00730 break; 00731 } 00732 while (pe == 0L); 00733 #endif 00734 00735 // Do common processing 00736 int protonum = -1; 00737 if (pe != NULL) 00738 protonum = pe->p_proto; 00739 00740 #ifdef HAVE_GETPROTOBYNAME_R 00741 delete [] buf; 00742 #endif 00743 00744 return protonum; 00745 } 00746 00747 int KResolver::servicePort(const char *servname, const char *protoname) 00748 { 00749 struct servent *se = 0L; 00750 #ifndef HAVE_GETSERVBYNAME_R 00751 QMutexLocker locker(&getXXbyYYmutex); 00752 00753 se = getservbyname(servname, protoname); 00754 00755 #else 00756 size_t buflen = 1024; 00757 struct servent servbuf; 00758 char *buf; 00759 do 00760 { 00761 buf = new char[buflen]; 00762 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL 00763 if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE)) 00764 # else 00765 if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00766 # endif 00767 { 00768 se = 0L; 00769 buflen += 1024; 00770 delete [] buf; 00771 } 00772 else 00773 break; 00774 } 00775 while (se == 0L); 00776 #endif 00777 00778 // Do common processing 00779 int servport = -1; 00780 if (se != NULL) 00781 servport = ntohs(se->s_port); 00782 00783 #ifdef HAVE_GETSERVBYNAME_R 00784 delete [] buf; 00785 #endif 00786 00787 return servport; 00788 } 00789 00790 QStrList KResolver::serviceName(const char* servname, const char *protoname) 00791 { 00792 struct servent *se = 0L; 00793 #ifndef HAVE_GETSERVBYNAME_R 00794 QMutexLocker locker(&getXXbyYYmutex); 00795 00796 se = getservbyname(servname, protoname); 00797 00798 #else 00799 size_t buflen = 1024; 00800 struct servent servbuf; 00801 char *buf; 00802 do 00803 { 00804 buf = new char[buflen]; 00805 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL 00806 if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE)) 00807 # else 00808 if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00809 # endif 00810 { 00811 se = 0L; 00812 buflen += 1024; 00813 delete [] buf; 00814 } 00815 else 00816 break; 00817 } 00818 while (se == 0L); 00819 #endif 00820 00821 // Do common processing 00822 QStrList lst(true); // use deep copies 00823 if (se != NULL) 00824 { 00825 lst.append(se->s_name); 00826 for (char **p = se->s_aliases; *p; p++) 00827 lst.append(*p); 00828 } 00829 00830 #ifdef HAVE_GETSERVBYNAME_R 00831 delete [] buf; 00832 #endif 00833 00834 return lst; 00835 } 00836 00837 QStrList KResolver::serviceName(int port, const char *protoname) 00838 { 00839 struct servent *se = 0L; 00840 #ifndef HAVE_GETSERVBYPORT_R 00841 QMutexLocker locker(&getXXbyYYmutex); 00842 00843 se = getservbyport(port, protoname); 00844 00845 #else 00846 size_t buflen = 1024; 00847 struct servent servbuf; 00848 char *buf; 00849 do 00850 { 00851 buf = new char[buflen]; 00852 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyport_r which returns struct *servent or NULL 00853 if ((se = getservbyport_r(port, protoname, &servbuf, buf, buflen)) && (errno == ERANGE)) 00854 # else 00855 if (getservbyport_r(port, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00856 # endif 00857 { 00858 se = 0L; 00859 buflen += 1024; 00860 delete [] buf; 00861 } 00862 else 00863 break; 00864 } 00865 while (se == 0L); 00866 #endif 00867 00868 // Do common processing 00869 QStrList lst(true); // use deep copies 00870 if (se != NULL) 00871 { 00872 lst.append(se->s_name); 00873 for (char **p = se->s_aliases; *p; p++) 00874 lst.append(*p); 00875 } 00876 00877 #ifdef HAVE_GETSERVBYPORT_R 00878 delete [] buf; 00879 #endif 00880 00881 return lst; 00882 } 00883 00884 QString KResolver::localHostName() 00885 { 00886 QCString name; 00887 int len; 00888 00889 #ifdef MAXHOSTNAMELEN 00890 len = MAXHOSTNAMELEN; 00891 #else 00892 len = 256; 00893 #endif 00894 00895 while (true) 00896 { 00897 name.resize(len); 00898 00899 if (gethostname(name.data(), len - 1) == 0) 00900 { 00901 // Call succeeded, but it's not guaranteed to be NUL-terminated 00902 // Note that some systems return success even if they did truncation 00903 name[len - 1] = '\0'; 00904 break; 00905 } 00906 00907 // Call failed 00908 if (errno == ENAMETOOLONG || errno == EINVAL) 00909 len += 256; 00910 else 00911 { 00912 // Oops! Unknown error! 00913 name = QCString(); 00914 } 00915 } 00916 00917 if (name.isEmpty()) 00918 return QString::fromLatin1("localhost"); 00919 00920 if (name.find('.') == -1) 00921 { 00922 // not fully qualified 00923 // must resolve 00924 KResolverResults results = resolve(name, "0", CanonName); 00925 if (results.isEmpty()) 00926 // cannot find a valid hostname! 00927 return QString::fromLatin1("localhost"); 00928 else 00929 return results.first().canonicalName(); 00930 } 00931 00932 return domainToUnicode(name); 00933 } 00934 00935 00936 // forward declaration 00937 static QStringList splitLabels(const QString& unicodeDomain); 00938 static QCString ToASCII(const QString& label); 00939 static QString ToUnicode(const QString& label); 00940 00941 static QStringList *KResolver_initIdnDomains() 00942 { 00943 const char *kde_use_idn = getenv("KDE_USE_IDN"); 00944 if (!kde_use_idn) 00945 kde_use_idn = "ac:at:br:cat:ch:cl:cn:de:dk:fi:gr:hu:info:io:is:jp:kr:li:lt:museum:org:no:se:sh:th:tm:tw:vn"; 00946 return new QStringList(QStringList::split(':', QString::fromLatin1(kde_use_idn).lower())); 00947 } 00948 00949 // implement the ToAscii function, as described by IDN documents 00950 QCString KResolver::domainToAscii(const QString& unicodeDomain) 00951 { 00952 if (!idnDomains) 00953 idnDomains = KResolver_initIdnDomains(); 00954 00955 QCString retval; 00956 // RFC 3490, section 4 describes the operation: 00957 // 1) this is a query, so don't allow unassigned 00958 00959 // 2) split the domain into individual labels, without 00960 // separators. 00961 QStringList input = splitLabels(unicodeDomain); 00962 00963 // Do we allow IDN names for this TLD? 00964 if (input.count() && !idnDomains->contains(input[input.count()-1].lower())) 00965 return input.join(".").lower().latin1(); // No IDN allowed for this TLD 00966 00967 // 3) decide whether to enforce the STD3 rules for chars < 0x7F 00968 // we don't enforce 00969 00970 // 4) for each label, apply ToASCII 00971 QStringList::Iterator it = input.begin(); 00972 const QStringList::Iterator end = input.end(); 00973 for ( ; it != end; ++it) 00974 { 00975 QCString cs = ToASCII(*it); 00976 if (cs.isNull()) 00977 return QCString(); // error! 00978 00979 // no, all is Ok. 00980 if (!retval.isEmpty()) 00981 retval += '.'; 00982 retval += cs; 00983 } 00984 00985 return retval; 00986 } 00987 00988 QString KResolver::domainToUnicode(const QCString& asciiDomain) 00989 { 00990 return domainToUnicode(QString::fromLatin1(asciiDomain)); 00991 } 00992 00993 // implement the ToUnicode function, as described by IDN documents 00994 QString KResolver::domainToUnicode(const QString& asciiDomain) 00995 { 00996 if (asciiDomain.isEmpty()) 00997 return asciiDomain; 00998 if (!idnDomains) 00999 idnDomains = KResolver_initIdnDomains(); 01000 01001 QString retval; 01002 01003 // draft-idn-idna-14.txt, section 4 describes the operation: 01004 // 1) this is a query, so don't allow unassigned 01005 // besides, input is ASCII 01006 01007 // 2) split the domain into individual labels, without 01008 // separators. 01009 QStringList input = splitLabels(asciiDomain); 01010 01011 // Do we allow IDN names for this TLD? 01012 if (input.count() && !idnDomains->contains(input[input.count()-1].lower())) 01013 return asciiDomain.lower(); // No TLDs allowed 01014 01015 // 3) decide whether to enforce the STD3 rules for chars < 0x7F 01016 // we don't enforce 01017 01018 // 4) for each label, apply ToUnicode 01019 QStringList::Iterator it; 01020 const QStringList::Iterator end = input.end(); 01021 for (it = input.begin(); it != end; ++it) 01022 { 01023 QString label = ToUnicode(*it).lower(); 01024 01025 // ToUnicode can't fail 01026 if (!retval.isEmpty()) 01027 retval += '.'; 01028 retval += label; 01029 } 01030 01031 return retval; 01032 } 01033 01034 QString KResolver::normalizeDomain(const QString& domain) 01035 { 01036 return domainToUnicode(domainToAscii(domain)); 01037 } 01038 01039 void KResolver::virtual_hook( int, void* ) 01040 { /*BASE::virtual_hook( id, data );*/ } 01041 01042 // here follows IDN functions 01043 // all IDN functions conform to the following documents: 01044 // RFC 3454 - Preparation of Internationalized Strings 01045 // RFC 3490 - Internationalizing Domain Names in Applications (IDNA) 01046 // RFC 3491 - Nameprep: A Stringprep Profile for 01047 // Internationalized Domain Names (IDN 01048 // RFC 3492 - Punycode: A Bootstring encoding of Unicode 01049 // for Internationalized Domain Names in Applications (IDNA) 01050 01051 static QStringList splitLabels(const QString& unicodeDomain) 01052 { 01053 // From RFC 3490 section 3.1: 01054 // "Whenever dots are used as label separators, the following characters 01055 // MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full 01056 // stop), U+FF0E (fullwidth full stop), U+FF61 (halfwidth ideographic full 01057 // stop)." 01058 static const unsigned int separators[] = { 0x002E, 0x3002, 0xFF0E, 0xFF61 }; 01059 01060 QStringList lst; 01061 int start = 0; 01062 uint i; 01063 for (i = 0; i < unicodeDomain.length(); i++) 01064 { 01065 unsigned int c = unicodeDomain[i].unicode(); 01066 01067 if (c == separators[0] || 01068 c == separators[1] || 01069 c == separators[2] || 01070 c == separators[3]) 01071 { 01072 // found a separator! 01073 lst << unicodeDomain.mid(start, i - start); 01074 start = i + 1; 01075 } 01076 } 01077 if ((long)i >= start) 01078 // there is still one left 01079 lst << unicodeDomain.mid(start, i - start); 01080 01081 return lst; 01082 } 01083 01084 static QCString ToASCII(const QString& label) 01085 { 01086 #ifdef HAVE_IDNA_H 01087 // We have idna.h, so we can use the idna_to_ascii 01088 // function :) 01089 01090 if (label.length() > 64) 01091 return (char*)0L; // invalid label 01092 01093 if (label.length() == 0) 01094 // this is allowed 01095 return QCString(""); // empty, not null 01096 01097 QCString retval; 01098 char buf[65]; 01099 01100 Q_UINT32* ucs4 = new Q_UINT32[label.length() + 1]; 01101 01102 uint i; 01103 for (i = 0; i < label.length(); i++) 01104 ucs4[i] = (unsigned long)label[i].unicode(); 01105 ucs4[i] = 0; // terminate with NUL, just to be on the safe side 01106 01107 if (idna_to_ascii_4i(ucs4, label.length(), buf, 0) == IDNA_SUCCESS) 01108 // success! 01109 retval = buf; 01110 01111 delete [] ucs4; 01112 return retval; 01113 #else 01114 return label.latin1(); 01115 #endif 01116 } 01117 01118 static QString ToUnicode(const QString& label) 01119 { 01120 #ifdef HAVE_IDNA_H 01121 // We have idna.h, so we can use the idna_to_unicode 01122 // function :) 01123 01124 Q_UINT32 *ucs4_input, *ucs4_output; 01125 size_t outlen; 01126 01127 ucs4_input = new Q_UINT32[label.length() + 1]; 01128 for (uint i = 0; i < label.length(); i++) 01129 ucs4_input[i] = (unsigned long)label[i].unicode(); 01130 01131 // try the same length for output 01132 ucs4_output = new Q_UINT32[outlen = label.length()]; 01133 01134 idna_to_unicode_44i(ucs4_input, label.length(), 01135 ucs4_output, &outlen, 01136 0); 01137 01138 if (outlen > label.length()) 01139 { 01140 // it must have failed 01141 delete [] ucs4_output; 01142 ucs4_output = new Q_UINT32[outlen]; 01143 01144 idna_to_unicode_44i(ucs4_input, label.length(), 01145 ucs4_output, &outlen, 01146 0); 01147 } 01148 01149 // now set the answer 01150 QString result; 01151 result.setLength(outlen); 01152 for (uint i = 0; i < outlen; i++) 01153 result[i] = (unsigned int)ucs4_output[i]; 01154 01155 delete [] ucs4_input; 01156 delete [] ucs4_output; 01157 01158 return result; 01159 #else 01160 return label; 01161 #endif 01162 } 01163 01164 #include "kresolver.moc"