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