• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

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

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.7.1
This website is maintained by Timothy Pearson.