kdecore Library: kresolver.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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"

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:10 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003