kdecore Library API Documentation

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