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