kdecore Library API Documentation

kresolver.cpp

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