kdecore Library API Documentation

kresolver.cpp

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