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