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     return true;
00467   else
00468     {
00469       QTime t;
00470       t.start();
00471 
00472       while (!msec || t.elapsed() < msec)
00473     {
00474       // wait on the manager to broadcast completion
00475       d->waiting = true;
00476       if (msec)
00477         KResolverManager::manager()->notifyWaiters.wait(&d->mutex, msec - t.elapsed());
00478       else
00479         KResolverManager::manager()->notifyWaiters.wait(&d->mutex);
00480 
00481       // the manager has processed
00482       // see if this object is done
00483       if (!isRunning())
00484         {
00485           // it's done
00486           d->waiting = false;
00487           emitFinished();
00488           return true;
00489         }
00490     }
00491 
00492       // if we've got here, we've timed out
00493       d->waiting = false;
00494       return false;
00495     }
00496 }
00497 
00498 void KResolver::cancel(bool emitSignal)
00499 {
00500   KResolverManager::manager()->dequeue(this);
00501   if (emitSignal)
00502     emitFinished();
00503 }
00504 
00505 KResolverResults
00506 KResolver::results() const
00507 {
00508   if (!isRunning())
00509     return d->results;
00510 
00511   // return a dummy, empty result
00512   KResolverResults r;
00513   r.setAddress(d->input.node, d->input.service);
00514   r.setError(d->errorcode, d->syserror);
00515   return r;
00516 }
00517 
00518 bool KResolver::event(QEvent* e)
00519 {
00520   if (static_cast<int>(e->type()) == KResolverManager::ResolutionCompleted)
00521     {
00522       emitFinished();
00523       return true;
00524     }
00525 
00526   return false;
00527 }
00528 
00529 void KResolver::emitFinished()
00530 {
00531   if (isRunning())
00532     d->status = KResolver::Success;
00533 
00534   QGuardedPtr<QObject> p = this; // guard against deletion
00535 
00536   emit finished(d->results);
00537 
00538   if (p && d->deleteWhenDone)
00539     deleteLater();      // in QObject
00540 }
00541 
00542 QString KResolver::errorString(int errorcode, int syserror)
00543 {
00544   // no i18n now...
00545   static const char * const messages[] =
00546   {
00547     I18N_NOOP("no error"),  // NoError
00548     I18N_NOOP("requested family not supported for this host name"), // AddrFamily
00549     I18N_NOOP("temporary failure in name resolution"),  // TryAgain
00550     I18N_NOOP("non-recoverable failure in name resolution"), // NonRecoverable
00551     I18N_NOOP("invalid flags"),         // BadFlags
00552     I18N_NOOP("memory allocation failure"), // Memory
00553     I18N_NOOP("name or service not known"), // NoName
00554     I18N_NOOP("requested family not supported"),    // UnsupportedFamily
00555     I18N_NOOP("requested service not supported for this socket type"), // UnsupportedService
00556     I18N_NOOP("requested socket type not supported"),   // UnsupportedSocketType
00557     I18N_NOOP("unknown error"),         // UnknownError
00558     I18N_NOOP2("1: the i18n'ed system error code, from errno",
00559           "system error: %1")       // SystemError
00560   };
00561 
00562   // handle the special value
00563   if (errorcode == Canceled)
00564     return i18n("request was canceled");
00565 
00566   if (errorcode > 0 || errorcode < SystemError)
00567     return QString::null;
00568 
00569   QString msg = i18n(messages[-errorcode]);
00570   if (errorcode == SystemError)
00571     msg.arg(QString::fromLocal8Bit(strerror(syserror)));
00572 
00573   return msg;
00574 }
00575 
00576 KResolverResults
00577 KResolver::resolve(const QString& host, const QString& service, int flags,
00578           int families)
00579 {
00580   KResolver qres(host, service, qApp, "synchronous KResolver");
00581   qres.setFlags(flags);
00582   qres.setFamily(families);
00583   qres.start();
00584   qres.wait();
00585   return qres.results();
00586 }
00587 
00588 bool KResolver::resolveAsync(QObject* userObj, const char *userSlot,
00589                  const QString& host, const QString& service,
00590                  int flags, int families)
00591 {
00592   KResolver* qres = new KResolver(host, service, qApp, "asynchronous KResolver");
00593   QObject::connect(qres, SIGNAL(finished(KResolverResults)), userObj, userSlot);
00594   qres->setFlags(flags);
00595   qres->setFamily(families);
00596   qres->d->deleteWhenDone = true; // this is the only difference from the example code
00597   return qres->start();
00598 }
00599 
00600 QStrList KResolver::protocolName(int protonum)
00601 {
00602   struct protoent *pe;
00603 #ifndef HAVE_GETPROTOBYNAME_R
00604   QMutexLocker locker(&getXXbyYYmutex);
00605 
00606   pe = getprotobynumber(protonum);
00607 
00608 #else
00609   size_t buflen = 1024;
00610   struct protoent protobuf;
00611   char *buf;
00612   do
00613     {
00614       buf = new char[buflen];
00615 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobynumber_r which returns struct *protoent or NULL
00616       if ((pe = getprotobynumber_r(protonum, &protobuf, buf, buflen)) && (errno == ERANGE))
00617 # else
00618       if (getprotobynumber_r(protonum, &protobuf, buf, buflen, &pe) == ERANGE)
00619 # endif
00620     {
00621       buflen += 1024;
00622       delete [] buf;
00623     }
00624       else
00625     break;
00626     }
00627   while (pe == 0L);
00628 #endif
00629 
00630   // Do common processing
00631   QStrList lst(true);   // use deep copies
00632   if (pe != NULL)
00633     {
00634       lst.append(pe->p_name);
00635       for (char **p = pe->p_aliases; *p; p++)
00636     lst.append(*p);
00637     }
00638 
00639 #ifdef HAVE_GETPROTOBYNAME_R
00640   delete [] buf;
00641 #endif
00642 
00643   return lst;
00644 }
00645 
00646 QStrList KResolver::protocolName(const char *protoname)
00647 {
00648   struct protoent *pe;
00649 #ifndef HAVE_GETPROTOBYNAME_R
00650   QMutexLocker locker(&getXXbyYYmutex);
00651 
00652   pe = getprotobyname(protoname);
00653 
00654 #else
00655   size_t buflen = 1024;
00656   struct protoent protobuf;
00657   char *buf;
00658   do
00659     {
00660       buf = new char[buflen];
00661 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL
00662       if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE))
00663 # else
00664       if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE)
00665 # endif
00666     {
00667       buflen += 1024;
00668       delete [] buf;
00669     }
00670       else
00671     break;
00672     }
00673   while (pe == 0L);
00674 #endif
00675 
00676   // Do common processing
00677   QStrList lst(true);   // use deep copies
00678   if (pe != NULL)
00679     {
00680       lst.append(pe->p_name);
00681       for (char **p = pe->p_aliases; *p; p++)
00682     lst.append(*p);
00683     }
00684 
00685 #ifdef HAVE_GETPROTOBYNAME_R
00686   delete [] buf;
00687 #endif
00688 
00689   return lst;
00690 }
00691 
00692 int KResolver::protocolNumber(const char *protoname)
00693 {
00694   struct protoent *pe;
00695 #ifndef HAVE_GETPROTOBYNAME_R
00696   QMutexLocker locker(&getXXbyYYmutex);
00697 
00698   pe = getprotobyname(protoname);
00699 
00700 #else
00701   size_t buflen = 1024;
00702   struct protoent protobuf;
00703   char *buf;
00704   do
00705     {
00706       buf = new char[buflen];
00707 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL
00708       if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE))
00709 # else
00710       if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE)
00711 # endif
00712     {
00713       buflen += 1024;
00714       delete [] buf;
00715     }
00716       else
00717     break;
00718     }
00719   while (pe == 0L);
00720 #endif
00721 
00722   // Do common processing
00723   int protonum = -1;
00724   if (pe != NULL)
00725     protonum = pe->p_proto;
00726 
00727 #ifdef HAVE_GETPROTOBYNAME_R
00728   delete [] buf;
00729 #endif
00730 
00731   return protonum;
00732 }
00733 
00734 int KResolver::servicePort(const char *servname, const char *protoname)
00735 {
00736   struct servent *se;
00737 #ifndef HAVE_GETSERVBYNAME_R
00738   QMutexLocker locker(&getXXbyYYmutex);
00739 
00740   se = getservbyname(servname, protoname);
00741 
00742 #else
00743   size_t buflen = 1024;
00744   struct servent servbuf;
00745   char *buf;
00746   do
00747     {
00748       buf = new char[buflen];
00749 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL
00750       if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
00751 # else
00752       if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE)
00753 # endif
00754     {
00755       buflen += 1024;
00756       delete [] buf;
00757     }
00758       else
00759     break;
00760     }
00761   while (se == 0L);
00762 #endif
00763 
00764   // Do common processing
00765   int servport = -1;
00766   if (se != NULL)
00767     servport = ntohs(se->s_port);
00768 
00769 #ifdef HAVE_GETSERVBYNAME_R
00770   delete [] buf;
00771 #endif
00772 
00773   return servport;
00774 }
00775 
00776 QStrList KResolver::serviceName(const char* servname, const char *protoname)
00777 {
00778   struct servent *se;
00779 #ifndef HAVE_GETSERVBYNAME_R
00780   QMutexLocker locker(&getXXbyYYmutex);
00781 
00782   se = getservbyname(servname, protoname);
00783 
00784 #else
00785   size_t buflen = 1024;
00786   struct servent servbuf;
00787   char *buf;
00788   do
00789     {
00790       buf = new char[buflen];
00791 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL
00792       if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
00793 # else
00794       if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE)
00795 # endif
00796     {
00797       buflen += 1024;
00798       delete [] buf;
00799     }
00800       else
00801     break;
00802     }
00803   while (se == 0L);
00804 #endif
00805 
00806   // Do common processing
00807   QStrList lst(true);   // use deep copies
00808   if (se != NULL)
00809     {
00810       lst.append(se->s_name);
00811       for (char **p = se->s_aliases; *p; p++)
00812     lst.append(*p);
00813     }
00814 
00815 #ifdef HAVE_GETSERVBYNAME_R
00816   delete [] buf;
00817 #endif
00818 
00819   return lst;
00820 }
00821 
00822 QStrList KResolver::serviceName(int port, const char *protoname)
00823 {
00824   struct servent *se;
00825 #ifndef HAVE_GETSERVBYPORT_R
00826   QMutexLocker locker(&getXXbyYYmutex);
00827 
00828   se = getservbyport(port, protoname);
00829 
00830 #else
00831   size_t buflen = 1024;
00832   struct servent servbuf;
00833   char *buf;
00834   do
00835     {
00836       buf = new char[buflen];
00837 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyport_r which returns struct *servent or NULL
00838       if ((se = getservbyport_r(port, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
00839 # else
00840       if (getservbyport_r(port, protoname, &servbuf, buf, buflen, &se) == ERANGE)
00841 # endif
00842     {
00843       buflen += 1024;
00844       delete [] buf;
00845     }
00846       else
00847     break;
00848     }
00849   while (se == 0L);
00850 #endif
00851 
00852   // Do common processing
00853   QStrList lst(true);   // use deep copies
00854   if (se != NULL)
00855     {
00856       lst.append(se->s_name);
00857       for (char **p = se->s_aliases; *p; p++)
00858     lst.append(*p);
00859     }
00860 
00861 #ifdef HAVE_GETSERVBYPORT_R
00862   delete [] buf;
00863 #endif
00864 
00865   return lst;
00866 }
00867 
00868 // forward declaration
00869 static QStringList splitLabels(const QString& unicodeDomain);
00870 static QCString ToASCII(const QString& label);
00871 static QString ToUnicode(const QString& label);
00872 
00873 static QStringList *KResolver_initIdnDomains()
00874 {
00875   const char *kde_use_idn = getenv("KDE_USE_IDN");
00876   if (!kde_use_idn)
00877      kde_use_idn = "at:ch:cn:de:dk:kr:jp:li:no:se:tw";
00878   return new QStringList(QStringList::split(':', QString::fromLatin1(kde_use_idn).lower()));
00879 }
00880 
00881 // implement the ToAscii function, as described by IDN documents
00882 QCString KResolver::domainToAscii(const QString& unicodeDomain)
00883 {
00884   if (!idnDomains)
00885     idnDomains = KResolver_initIdnDomains();
00886 
00887   QCString retval;
00888   // RFC 3490, section 4 describes the operation:
00889   // 1) this is a query, so don't allow unassigned
00890 
00891   // 2) split the domain into individual labels, without
00892   // separators.
00893   QStringList input = splitLabels(unicodeDomain);
00894 
00895   // Do we allow IDN names for this TLD?
00896   if (input.count() && !idnDomains->contains(input[input.count()-1].lower()))
00897     return input.join(".").lower().latin1(); // No IDN allowed for this TLD
00898 
00899   // 3) decide whether to enforce the STD3 rules for chars < 0x7F
00900   // we don't enforce
00901 
00902   // 4) for each label, apply ToASCII
00903   QStringList::Iterator it = input.begin();
00904   const QStringList::Iterator end = input.end();
00905   for ( ; it != end; ++it)
00906     {
00907       QCString cs = ToASCII(*it);
00908       if (cs.isNull())
00909     return QCString();  // error!
00910 
00911       // no, all is Ok.
00912       if (!retval.isEmpty())
00913     retval += '.';
00914       retval += cs;
00915     }
00916 
00917   return retval;
00918 }
00919 
00920 QString KResolver::domainToUnicode(const QCString& asciiDomain)
00921 {
00922   return domainToUnicode(QString::fromLatin1(asciiDomain));
00923 }
00924 
00925 // implement the ToUnicode function, as described by IDN documents
00926 QString KResolver::domainToUnicode(const QString& asciiDomain)
00927 {
00928   if (asciiDomain.isEmpty())
00929     return asciiDomain;
00930   if (!idnDomains)
00931     idnDomains = KResolver_initIdnDomains();
00932 
00933   QString retval;
00934 
00935   // draft-idn-idna-14.txt, section 4 describes the operation:
00936   // 1) this is a query, so don't allow unassigned
00937   //   besides, input is ASCII
00938 
00939   // 2) split the domain into individual labels, without
00940   // separators.
00941   QStringList input = splitLabels(asciiDomain);
00942 
00943   // Do we allow IDN names for this TLD?
00944   if (input.count() && !idnDomains->contains(input[input.count()-1].lower()))
00945     return asciiDomain.lower(); // No TLDs allowed
00946 
00947   // 3) decide whether to enforce the STD3 rules for chars < 0x7F
00948   // we don't enforce
00949 
00950   // 4) for each label, apply ToUnicode
00951   QStringList::Iterator it;
00952   const QStringList::Iterator end = input.end();
00953   for (it = input.begin(); it != end; ++it)
00954     {
00955       QString label = ToUnicode(*it).lower();
00956 
00957       // ToUnicode can't fail
00958       if (!retval.isEmpty())
00959     retval += '.';
00960       retval += label;
00961     }
00962 
00963   return retval;
00964 }
00965 
00966 QString KResolver::normalizeDomain(const QString& domain)
00967 {
00968   return domainToUnicode(domainToAscii(domain));
00969 }
00970 
00971 void KResolver::virtual_hook( int, void* )
00972 { /*BASE::virtual_hook( id, data );*/ }
00973 
00974 // here follows IDN functions
00975 // all IDN functions conform to the following documents:
00976 //  RFC 3454 - Preparation of Internationalized Strings
00977 //  RFC 3490 - Internationalizing Domain Names in Applications (IDNA)
00978 //  RFC 3491 - Nameprep: A Stringprep Profile for
00979 //                Internationalized Domain Names (IDN
00980 //  RFC 3492 - Punycode: A Bootstring encoding of Unicode
00981 //          for Internationalized Domain Names in Applications (IDNA)
00982 
00983 static QStringList splitLabels(const QString& unicodeDomain)
00984 {
00985   // From RFC 3490 section 3.1:
00986   // "Whenever dots are used as label separators, the following characters
00987   // MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full
00988   // stop), U+FF0E (fullwidth full stop), U+FF61 (halfwidth ideographic full
00989   // stop)."
00990   static const unsigned int separators[] = { 0x002E, 0x3002, 0xFF0E, 0xFF61 };
00991 
00992   QStringList lst;
00993   int start = 0;
00994   uint i;
00995   for (i = 0; i < unicodeDomain.length(); i++)
00996     {
00997       unsigned int c = unicodeDomain[i].unicode();
00998 
00999       if (c == separators[0] ||
01000       c == separators[1] ||
01001       c == separators[2] ||
01002       c == separators[3])
01003     {
01004       // found a separator!
01005       lst << unicodeDomain.mid(start, i - start);
01006       start = i + 1;
01007     }
01008     }
01009   if ((long)i >= start)
01010     // there is still one left
01011     lst << unicodeDomain.mid(start, i - start);
01012 
01013   return lst;
01014 }
01015 
01016 static QCString ToASCII(const QString& label)
01017 {
01018 #ifdef HAVE_IDNA_H
01019   // We have idna.h, so we can use the idna_to_ascii
01020   // function :)
01021 
01022   if (label.length() > 64)
01023     return (char*)0L;       // invalid label
01024 
01025   if (label.length() == 0)
01026     // this is allowed
01027     return QCString("");    // empty, not null
01028 
01029   QCString retval;
01030   char buf[65];
01031 
01032   Q_UINT32* ucs4 = new Q_UINT32[label.length() + 1];
01033 
01034   uint i;
01035   for (i = 0; i < label.length(); i++)
01036     ucs4[i] = (unsigned long)label[i].unicode();
01037   ucs4[i] = 0;          // terminate with NUL, just to be on the safe side
01038 
01039   if (idna_to_ascii_4i(ucs4, label.length(), buf, 0) == IDNA_SUCCESS)
01040     // success!
01041     retval = buf;
01042 
01043   delete [] ucs4;
01044   return retval;
01045 #else
01046   return label.latin1();
01047 #endif
01048 }
01049 
01050 static QString ToUnicode(const QString& label)
01051 {
01052 #ifdef HAVE_IDNA_H
01053   // We have idna.h, so we can use the idna_to_unicode
01054   // function :)
01055 
01056   Q_UINT32 *ucs4_input, *ucs4_output;
01057   size_t outlen;
01058 
01059   ucs4_input = new Q_UINT32[label.length() + 1];
01060   for (uint i = 0; i < label.length(); i++)
01061     ucs4_input[i] = (unsigned long)label[i].unicode();
01062 
01063   // try the same length for output
01064   ucs4_output = new Q_UINT32[outlen = label.length()];
01065 
01066   idna_to_unicode_44i(ucs4_input, label.length(),
01067               ucs4_output, &outlen,
01068               0);
01069 
01070   if (outlen > label.length())
01071     {
01072       // it must have failed
01073       delete [] ucs4_output;
01074       ucs4_output = new Q_UINT32[outlen];
01075 
01076       idna_to_unicode_44i(ucs4_input, label.length(),
01077               ucs4_output, &outlen,
01078               0);
01079     }
01080 
01081   // now set the answer
01082   QString result;
01083   result.setLength(outlen);
01084   for (uint i = 0; i < outlen; i++)
01085     result[i] = (unsigned int)ucs4_output[i];
01086 
01087   delete [] ucs4_input;
01088   delete [] ucs4_output;
01089 
01090   return result;
01091 #else
01092   return label;
01093 #endif
01094 }
01095 
01096 #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 Wed May 4 07:11:22 2005 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003