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