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 <klocale.h> 00058 00059 // Us 00060 #include "kresolver.h" 00061 #include "kresolver_p.h" 00062 #include "ksocketaddress.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 KSocketAddress 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 KSocketAddress& 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 = KSocketAddress(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 KSocketAddress KResolverEntry::address() const 00143 { 00144 return d ? d->addr : KSocketAddress(); 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("KDE_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"