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

kdecore

  • kdecore
  • network
kresolver.cpp
1 /* -*- C++ -*-
2  * Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net>
3  *
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include "config.h"
26 
27 // System includes
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/param.h>
31 #include <errno.h>
32 #include <netdb.h>
33 #include <time.h>
34 #include <arpa/inet.h>
35 #include <netinet/in.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 
39 // Qt includes
40 #include <tqapplication.h>
41 #include <tqstring.h>
42 #include <tqcstring.h>
43 #include <tqstrlist.h>
44 #include <tqstringlist.h>
45 #include <tqshared.h>
46 #include <tqdatetime.h>
47 #include <tqtimer.h>
48 #include <tqmutex.h>
49 #include <tqguardedptr.h>
50 
51 // IDN
52 #ifdef HAVE_IDNA_H
53 # include <idna.h>
54 #endif
55 
56 // KDE
57 #include <klocale.h>
58 
59 // Us
60 #include "kresolver.h"
61 #include "kresolver_p.h"
62 #include "ksocketaddress.h"
63 
64 #ifdef NEED_MUTEX
65 #warning "mutex"
66 TQMutex getXXbyYYmutex;
67 #endif
68 
69 using namespace KNetwork;
70 using namespace KNetwork::Internal;
71 
73 // class KResolverEntry
74 
75 class KNetwork::KResolverEntryPrivate: public TQShared
76 {
77 public:
78  KSocketAddress addr;
79  int socktype;
80  int protocol;
81  TQString canonName;
82  TQCString encodedName;
83 
84  inline KResolverEntryPrivate() :
85  socktype(0), protocol(0)
86  { }
87 };
88 
89 // default constructor
90 KResolverEntry::KResolverEntry() :
91  d(0L)
92 {
93 }
94 
95 // constructor with stuff
96 KResolverEntry::KResolverEntry(const KSocketAddress& addr, int socktype, int protocol,
97  const TQString& canonName, const TQCString& encodedName) :
98  d(new KResolverEntryPrivate)
99 {
100  d->addr = addr;
101  d->socktype = socktype;
102  d->protocol = protocol;
103  d->canonName = canonName;
104  d->encodedName = encodedName;
105 }
106 
107 // constructor with even more stuff
108 KResolverEntry::KResolverEntry(const struct sockaddr* sa, TQ_UINT16 salen, int socktype,
109  int protocol, const TQString& canonName,
110  const TQCString& encodedName) :
111  d(new KResolverEntryPrivate)
112 {
113  d->addr = KSocketAddress(sa, salen);
114  d->socktype = socktype;
115  d->protocol = protocol;
116  d->canonName = canonName;
117  d->encodedName = encodedName;
118 }
119 
120 // copy constructor
121 KResolverEntry::KResolverEntry(const KResolverEntry& that) :
122  d(0L)
123 {
124  *this = that;
125 }
126 
127 // destructor
128 KResolverEntry::~KResolverEntry()
129 {
130  if (d == 0L)
131  return;
132 
133  if (d->deref())
134  delete d;
135 }
136 
137 // returns the socket address
138 KSocketAddress KResolverEntry::address() const
139 {
140  return d ? d->addr : KSocketAddress();
141 }
142 
143 // returns the length
144 TQ_UINT16 KResolverEntry::length() const
145 {
146  return d ? d->addr.length() : 0;
147 }
148 
149 // returns the family
150 int KResolverEntry::family() const
151 {
152  return d ? d->addr.family() : AF_UNSPEC;
153 }
154 
155 // returns the canonical name
156 TQString KResolverEntry::canonicalName() const
157 {
158  return d ? d->canonName : TQString::null;
159 }
160 
161 // returns the encoded name
162 TQCString KResolverEntry::encodedName() const
163 {
164  return d ? d->encodedName : TQCString();
165 }
166 
167 // returns the socket type
168 int KResolverEntry::socketType() const
169 {
170  return d ? d->socktype : 0;
171 }
172 
173 // returns the protocol
174 int KResolverEntry::protocol() const
175 {
176  return d ? d->protocol : 0;
177 }
178 
179 // assignment operator
180 KResolverEntry& KResolverEntry::operator= (const KResolverEntry& that)
181 {
182  // copy the data
183  if (that.d)
184  that.d->ref();
185 
186  if (d && d->deref())
187  delete d;
188 
189  d = that.d;
190  return *this;
191 }
192 
194 // class KResolverResults
195 
196 class KNetwork::KResolverResultsPrivate
197 {
198 public:
199  TQString node, service;
200  int errorcode, syserror;
201 
202  KResolverResultsPrivate() :
203  errorcode(0), syserror(0)
204  { }
205 };
206 
207 // default constructor
208 KResolverResults::KResolverResults()
209  : d(new KResolverResultsPrivate)
210 {
211 }
212 
213 // copy constructor
214 KResolverResults::KResolverResults(const KResolverResults& other)
215  : TQValueList<KResolverEntry>(other), d(new KResolverResultsPrivate)
216 {
217  *d = *other.d;
218 }
219 
220 // destructor
221 KResolverResults::~KResolverResults()
222 {
223  delete d;
224 }
225 
226 // assignment operator
227 KResolverResults&
228 KResolverResults::operator= (const KResolverResults& other)
229 {
230  if (this == &other)
231  return *this;
232 
233  // copy over the other data
234  *d = *other.d;
235 
236  // now let TQValueList do the rest of the work
237  TQValueList<KResolverEntry>::operator =(other);
238 
239  return *this;
240 }
241 
242 // gets the error code
243 int KResolverResults::error() const
244 {
245  return d->errorcode;
246 }
247 
248 // gets the system errno
249 int KResolverResults::systemError() const
250 {
251  return d->syserror;
252 }
253 
254 // sets the error codes
255 void KResolverResults::setError(int errorcode, int systemerror)
256 {
257  d->errorcode = errorcode;
258  d->syserror = systemerror;
259 }
260 
261 // gets the hostname
262 TQString KResolverResults::nodeName() const
263 {
264  return d->node;
265 }
266 
267 // gets the service name
268 TQString KResolverResults::serviceName() const
269 {
270  return d->service;
271 }
272 
273 // sets the address
274 void KResolverResults::setAddress(const TQString& node,
275  const TQString& service)
276 {
277  d->node = node;
278  d->service = service;
279 }
280 
281 void KResolverResults::virtual_hook( int, void* )
282 { /*BASE::virtual_hook( id, data );*/ }
283 
284 
286 // class KResolver
287 
288 TQStringList *KResolver::idnDomains = 0;
289 
290 
291 // default constructor
292 KResolver::KResolver(TQObject *parent, const char *name)
293  : TQObject(parent, name), d(new KResolverPrivate(this))
294 {
295 }
296 
297 // constructor with host and service
298 KResolver::KResolver(const TQString& nodename, const TQString& servicename,
299  TQObject *parent, const char *name)
300  : TQObject(parent, name), d(new KResolverPrivate(this, nodename, servicename))
301 {
302 }
303 
304 // destructor
305 KResolver::~KResolver()
306 {
307  cancel(false);
308  delete d;
309 }
310 
311 // get the status
312 int KResolver::status() const
313 {
314  return d->status;
315 }
316 
317 // get the error code
318 int KResolver::error() const
319 {
320  return d->errorcode;
321 }
322 
323 // get the errno
324 int KResolver::systemError() const
325 {
326  return d->syserror;
327 }
328 
329 // are we running?
330 bool KResolver::isRunning() const
331 {
332  return d->status > 0 && d->status < Success;
333 }
334 
335 // get the hostname
336 TQString KResolver::nodeName() const
337 {
338  return d->input.node;
339 }
340 
341 // get the service
342 TQString KResolver::serviceName() const
343 {
344  return d->input.service;
345 }
346 
347 // sets the hostname
348 void KResolver::setNodeName(const TQString& nodename)
349 {
350  // don't touch those values if we're working!
351  if (!isRunning())
352  {
353  d->input.node = nodename;
354  d->status = Idle;
355  d->results.setAddress(nodename, d->input.service);
356  }
357 }
358 
359 // sets the service
360 void KResolver::setServiceName(const TQString& service)
361 {
362  // don't change if running
363  if (!isRunning())
364  {
365  d->input.service = service;
366  d->status = Idle;
367  d->results.setAddress(d->input.node, service);
368  }
369 }
370 
371 // sets the address
372 void KResolver::setAddress(const TQString& nodename, const TQString& service)
373 {
374  setNodeName(nodename);
375  setServiceName(service);
376 }
377 
378 // get the flags
379 int KResolver::flags() const
380 {
381  return d->input.flags;
382 }
383 
384 // sets the flags
385 int KResolver::setFlags(int flags)
386 {
387  int oldflags = d->input.flags;
388  if (!isRunning())
389  {
390  d->input.flags = flags;
391  d->status = Idle;
392  }
393  return oldflags;
394 }
395 
396 // sets the family mask
397 void KResolver::setFamily(int families)
398 {
399  if (!isRunning())
400  {
401  d->input.familyMask = families;
402  d->status = Idle;
403  }
404 }
405 
406 // sets the socket type
407 void KResolver::setSocketType(int type)
408 {
409  if (!isRunning())
410  {
411  d->input.socktype = type;
412  d->status = Idle;
413  }
414 }
415 
416 // sets the protocol
417 void KResolver::setProtocol(int protonum, const char *name)
418 {
419  if (isRunning())
420  return; // can't change now
421 
422  // we copy the given protocol name. If it isn't an empty string
423  // and the protocol number was 0, we will look it up in /etc/protocols
424  // we also leave the error reporting to the actual lookup routines, in
425  // case the given protocol name doesn't exist
426 
427  d->input.protocolName = name;
428  if (protonum == 0 && name != 0L && *name != '\0')
429  {
430  // must look up the protocol number
431  d->input.protocol = KResolver::protocolNumber(name);
432  }
433  else
434  d->input.protocol = protonum;
435  d->status = Idle;
436 }
437 
438 bool KResolver::start()
439 {
440  if (!isRunning())
441  {
442  d->results.empty();
443 
444  // is there anything to be queued?
445  if (d->input.node.isEmpty() && d->input.service.isEmpty())
446  {
447  d->status = KResolver::Success;
448  emitFinished();
449  }
450  else
451  KResolverManager::manager()->enqueue(this, 0L);
452  }
453 
454  return true;
455 }
456 
457 bool KResolver::wait(int msec)
458 {
459  if (!isRunning())
460  {
461  emitFinished();
462  return true;
463  }
464 
465  TQMutexLocker locker(&d->mutex);
466 
467  if (!isRunning())
468  {
469  // it was running and no longer is?
470  // That means the manager has finished its processing and has posted
471  // an event for the signal to be emitted already. This means the signal
472  // will be emitted twice!
473 
474  emitFinished();
475  return true;
476  }
477  else
478  {
479  TQTime t;
480  t.start();
481 
482  while (!msec || t.elapsed() < msec)
483  {
484  // wait on the manager to broadcast completion
485  d->waiting = true;
486  if (msec)
487  KResolverManager::manager()->notifyWaiters.wait(&d->mutex, msec - t.elapsed());
488  else
489  KResolverManager::manager()->notifyWaiters.wait(&d->mutex);
490 
491  // the manager has processed
492  // see if this object is done
493  if (!isRunning())
494  {
495  // it's done
496  d->waiting = false;
497  emitFinished();
498  return true;
499  }
500  }
501 
502  // if we've got here, we've timed out
503  d->waiting = false;
504  return false;
505  }
506 }
507 
508 void KResolver::cancel(bool emitSignal)
509 {
510  KResolverManager::manager()->dequeue(this);
511  if (emitSignal)
512  emitFinished();
513 }
514 
515 KResolverResults
516 KResolver::results() const
517 {
518  if (!isRunning())
519  return d->results;
520 
521  // return a dummy, empty result
522  KResolverResults r;
523  r.setAddress(d->input.node, d->input.service);
524  r.setError(d->errorcode, d->syserror);
525  return r;
526 }
527 
528 bool KResolver::event(TQEvent* e)
529 {
530  if (static_cast<int>(e->type()) == KResolverManager::ResolutionCompleted)
531  {
532  emitFinished();
533  return true;
534  }
535 
536  return false;
537 }
538 
539 void KResolver::emitFinished()
540 {
541  if (isRunning())
542  d->status = KResolver::Success;
543 
544  TQGuardedPtr<TQObject> p = this; // guard against deletion
545 
546  emit finished(d->results);
547 
548  if (p && d->deleteWhenDone)
549  deleteLater(); // in QObject
550 }
551 
552 TQString KResolver::errorString(int errorcode, int syserror)
553 {
554  // no i18n now...
555  static const char * const messages[] =
556  {
557  I18N_NOOP("no error"), // NoError
558  I18N_NOOP("requested family not supported for this host name"), // AddrFamily
559  I18N_NOOP("temporary failure in name resolution"), // TryAgain
560  I18N_NOOP("non-recoverable failure in name resolution"), // NonRecoverable
561  I18N_NOOP("invalid flags"), // BadFlags
562  I18N_NOOP("memory allocation failure"), // Memory
563  I18N_NOOP("name or service not known"), // NoName
564  I18N_NOOP("requested family not supported"), // UnsupportedFamily
565  I18N_NOOP("requested service not supported for this socket type"), // UnsupportedService
566  I18N_NOOP("requested socket type not supported"), // UnsupportedSocketType
567  I18N_NOOP("unknown error"), // UnknownError
568  I18N_NOOP2("1: the i18n'ed system error code, from errno",
569  "system error: %1") // SystemError
570  };
571 
572  // handle the special value
573  if (errorcode == Canceled)
574  return i18n("request was canceled");
575 
576  if (errorcode > 0 || errorcode < SystemError)
577  return TQString::null;
578 
579  TQString msg = i18n(messages[-errorcode]);
580  if (errorcode == SystemError)
581  msg.arg(TQString::fromLocal8Bit(strerror(syserror)));
582 
583  return msg;
584 }
585 
586 KResolverResults
587 KResolver::resolve(const TQString& host, const TQString& service, int flags,
588  int families)
589 {
590  KResolver qres(host, service, TQT_TQOBJECT(tqApp), "synchronous KResolver");
591  qres.setFlags(flags);
592  qres.setFamily(families);
593  qres.start();
594  qres.wait();
595  return qres.results();
596 }
597 
598 bool KResolver::resolveAsync(TQObject* userObj, const char *userSlot,
599  const TQString& host, const TQString& service,
600  int flags, int families)
601 {
602  KResolver* qres = new KResolver(host, service, TQT_TQOBJECT(tqApp), "asynchronous KResolver");
603  TQObject::connect(qres, TQT_SIGNAL(finished(KResolverResults)), userObj, userSlot);
604  qres->setFlags(flags);
605  qres->setFamily(families);
606  qres->d->deleteWhenDone = true; // this is the only difference from the example code
607  return qres->start();
608 }
609 
610 TQStrList KResolver::protocolName(int protonum)
611 {
612  struct protoent *pe = 0L;
613 #ifndef HAVE_GETPROTOBYNAME_R
614  TQMutexLocker locker(&getXXbyYYmutex);
615 
616  pe = getprotobynumber(protonum);
617 
618 #else
619  size_t buflen = 1024;
620  struct protoent protobuf;
621  char *buf;
622  do
623  {
624  buf = new char[buflen];
625 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobynumber_r which returns struct *protoent or NULL
626  if ((pe = getprotobynumber_r(protonum, &protobuf, buf, buflen)) && (errno == ERANGE))
627 # else
628  if (getprotobynumber_r(protonum, &protobuf, buf, buflen, &pe) == ERANGE)
629 # endif
630  {
631  pe = 0L;
632  buflen += 1024;
633  delete [] buf;
634  }
635  else
636  break;
637  }
638  while (pe == 0L);
639 #endif
640 
641  // Do common processing
642  TQStrList lst(true); // use deep copies
643  if (pe != NULL)
644  {
645  lst.append(pe->p_name);
646  for (char **p = pe->p_aliases; *p; p++)
647  lst.append(*p);
648  }
649 
650 #ifdef HAVE_GETPROTOBYNAME_R
651  delete [] buf;
652 #endif
653 
654  return lst;
655 }
656 
657 TQStrList KResolver::protocolName(const char *protoname)
658 {
659  struct protoent *pe = 0L;
660 #ifndef HAVE_GETPROTOBYNAME_R
661  TQMutexLocker locker(&getXXbyYYmutex);
662 
663  pe = getprotobyname(protoname);
664 
665 #else
666  size_t buflen = 1024;
667  struct protoent protobuf;
668  char *buf;
669  do
670  {
671  buf = new char[buflen];
672 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL
673  if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE))
674 # else
675  if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE)
676 # endif
677  {
678  pe = 0L;
679  buflen += 1024;
680  delete [] buf;
681  }
682  else
683  break;
684  }
685  while (pe == 0L);
686 #endif
687 
688  // Do common processing
689  TQStrList lst(true); // use deep copies
690  if (pe != NULL)
691  {
692  lst.append(pe->p_name);
693  for (char **p = pe->p_aliases; *p; p++)
694  lst.append(*p);
695  }
696 
697 #ifdef HAVE_GETPROTOBYNAME_R
698  delete [] buf;
699 #endif
700 
701  return lst;
702 }
703 
704 int KResolver::protocolNumber(const char *protoname)
705 {
706  struct protoent *pe = 0L;
707 #ifndef HAVE_GETPROTOBYNAME_R
708  TQMutexLocker locker(&getXXbyYYmutex);
709 
710  pe = getprotobyname(protoname);
711 
712 #else
713  size_t buflen = 1024;
714  struct protoent protobuf;
715  char *buf;
716  do
717  {
718  buf = new char[buflen];
719 # ifdef USE_SOLARIS // Solaris uses a 4 argument getprotobyname_r which returns struct *protoent or NULL
720  if ((pe = getprotobyname_r(protoname, &protobuf, buf, buflen)) && (errno == ERANGE))
721 # else
722  if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE)
723 # endif
724  {
725  pe = 0L;
726  buflen += 1024;
727  delete [] buf;
728  }
729  else
730  break;
731  }
732  while (pe == 0L);
733 #endif
734 
735  // Do common processing
736  int protonum = -1;
737  if (pe != NULL)
738  protonum = pe->p_proto;
739 
740 #ifdef HAVE_GETPROTOBYNAME_R
741  delete [] buf;
742 #endif
743 
744  return protonum;
745 }
746 
747 int KResolver::servicePort(const char *servname, const char *protoname)
748 {
749  struct servent *se = 0L;
750 #ifndef HAVE_GETSERVBYNAME_R
751  TQMutexLocker locker(&getXXbyYYmutex);
752 
753  se = getservbyname(servname, protoname);
754 
755 #else
756  size_t buflen = 1024;
757  struct servent servbuf;
758  char *buf;
759  do
760  {
761  buf = new char[buflen];
762 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL
763  if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
764 # else
765  if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE)
766 # endif
767  {
768  se = 0L;
769  buflen += 1024;
770  delete [] buf;
771  }
772  else
773  break;
774  }
775  while (se == 0L);
776 #endif
777 
778  // Do common processing
779  int servport = -1;
780  if (se != NULL)
781  servport = ntohs(se->s_port);
782 
783 #ifdef HAVE_GETSERVBYNAME_R
784  delete [] buf;
785 #endif
786 
787  return servport;
788 }
789 
790 TQStrList KResolver::serviceName(const char* servname, const char *protoname)
791 {
792  struct servent *se = 0L;
793 #ifndef HAVE_GETSERVBYNAME_R
794  TQMutexLocker locker(&getXXbyYYmutex);
795 
796  se = getservbyname(servname, protoname);
797 
798 #else
799  size_t buflen = 1024;
800  struct servent servbuf;
801  char *buf;
802  do
803  {
804  buf = new char[buflen];
805 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyname_r which returns struct *servent or NULL
806  if ((se = getservbyname_r(servname, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
807 # else
808  if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE)
809 # endif
810  {
811  se = 0L;
812  buflen += 1024;
813  delete [] buf;
814  }
815  else
816  break;
817  }
818  while (se == 0L);
819 #endif
820 
821  // Do common processing
822  TQStrList lst(true); // use deep copies
823  if (se != NULL)
824  {
825  lst.append(se->s_name);
826  for (char **p = se->s_aliases; *p; p++)
827  lst.append(*p);
828  }
829 
830 #ifdef HAVE_GETSERVBYNAME_R
831  delete [] buf;
832 #endif
833 
834  return lst;
835 }
836 
837 TQStrList KResolver::serviceName(int port, const char *protoname)
838 {
839  struct servent *se = 0L;
840 #ifndef HAVE_GETSERVBYPORT_R
841  TQMutexLocker locker(&getXXbyYYmutex);
842 
843  se = getservbyport(port, protoname);
844 
845 #else
846  size_t buflen = 1024;
847  struct servent servbuf;
848  char *buf;
849  do
850  {
851  buf = new char[buflen];
852 # ifdef USE_SOLARIS // Solaris uses a 5 argument getservbyport_r which returns struct *servent or NULL
853  if ((se = getservbyport_r(port, protoname, &servbuf, buf, buflen)) && (errno == ERANGE))
854 # else
855  if (getservbyport_r(port, protoname, &servbuf, buf, buflen, &se) == ERANGE)
856 # endif
857  {
858  se = 0L;
859  buflen += 1024;
860  delete [] buf;
861  }
862  else
863  break;
864  }
865  while (se == 0L);
866 #endif
867 
868  // Do common processing
869  TQStrList lst(true); // use deep copies
870  if (se != NULL)
871  {
872  lst.append(se->s_name);
873  for (char **p = se->s_aliases; *p; p++)
874  lst.append(*p);
875  }
876 
877 #ifdef HAVE_GETSERVBYPORT_R
878  delete [] buf;
879 #endif
880 
881  return lst;
882 }
883 
884 TQString KResolver::localHostName()
885 {
886  TQCString name;
887  int len;
888 
889 #ifdef MAXHOSTNAMELEN
890  len = MAXHOSTNAMELEN;
891 #else
892  len = 256;
893 #endif
894 
895  while (true)
896  {
897  name.resize(len);
898 
899  if (gethostname(name.data(), len - 1) == 0)
900  {
901  // Call succeeded, but it's not guaranteed to be NUL-terminated
902  // Note that some systems return success even if they did truncation
903  name[len - 1] = '\0';
904  break;
905  }
906 
907  // Call failed
908  if (errno == ENAMETOOLONG || errno == EINVAL)
909  len += 256;
910  else
911  {
912  // Oops! Unknown error!
913  name = TQCString();
914  }
915  }
916 
917  if (name.isEmpty())
918  return TQString::fromLatin1("localhost");
919 
920  if (name.find('.') == -1)
921  {
922  // not fully qualified
923  // must resolve
924  KResolverResults results = resolve(name, "0", CanonName);
925  if (results.isEmpty())
926  // cannot find a valid hostname!
927  return TQString::fromLatin1("localhost");
928  else
929  return results.first().canonicalName();
930  }
931 
932  return domainToUnicode(name);
933 }
934 
935 
936 // forward declaration
937 static TQStringList splitLabels(const TQString& unicodeDomain);
938 static TQCString ToASCII(const TQString& label);
939 static TQString ToUnicode(const TQString& label);
940 
941 static TQStringList *KResolver_initIdnDomains()
942 {
943  const char *kde_use_idn = getenv("KDE_USE_IDN");
944  if (!kde_use_idn)
945  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";
946  return new TQStringList(TQStringList::split(':', TQString::fromLatin1(kde_use_idn).lower()));
947 }
948 
949 // implement the ToAscii function, as described by IDN documents
950 TQCString KResolver::domainToAscii(const TQString& unicodeDomain)
951 {
952  if (!idnDomains)
953  idnDomains = KResolver_initIdnDomains();
954 
955  TQCString retval;
956  // RFC 3490, section 4 describes the operation:
957  // 1) this is a query, so don't allow unassigned
958 
959  // 2) split the domain into individual labels, without
960  // separators.
961  TQStringList input = splitLabels(unicodeDomain);
962 
963  // Do we allow IDN names for this TLD?
964  if (input.count() && !idnDomains->contains(input[input.count()-1].lower()))
965  return input.join(".").lower().latin1(); // No IDN allowed for this TLD
966 
967  // 3) decide whether to enforce the STD3 rules for chars < 0x7F
968  // we don't enforce
969 
970  // 4) for each label, apply ToASCII
971  TQStringList::Iterator it = input.begin();
972  const TQStringList::Iterator end = input.end();
973  for ( ; it != end; ++it)
974  {
975  TQCString cs = ToASCII(*it);
976  if (cs.isNull())
977  return TQCString(); // error!
978 
979  // no, all is Ok.
980  if (!retval.isEmpty())
981  retval += '.';
982  retval += cs;
983  }
984 
985  return retval;
986 }
987 
988 TQString KResolver::domainToUnicode(const TQCString& asciiDomain)
989 {
990  return domainToUnicode(TQString::fromLatin1(asciiDomain));
991 }
992 
993 // implement the ToUnicode function, as described by IDN documents
994 TQString KResolver::domainToUnicode(const TQString& asciiDomain)
995 {
996  if (asciiDomain.isEmpty())
997  return asciiDomain;
998  if (!idnDomains)
999  idnDomains = KResolver_initIdnDomains();
1000 
1001  TQString retval;
1002 
1003  // draft-idn-idna-14.txt, section 4 describes the operation:
1004  // 1) this is a query, so don't allow unassigned
1005  // besides, input is ASCII
1006 
1007  // 2) split the domain into individual labels, without
1008  // separators.
1009  TQStringList input = splitLabels(asciiDomain);
1010 
1011  // Do we allow IDN names for this TLD?
1012  if (input.count() && !idnDomains->contains(input[input.count()-1].lower()))
1013  return asciiDomain.lower(); // No TLDs allowed
1014 
1015  // 3) decide whether to enforce the STD3 rules for chars < 0x7F
1016  // we don't enforce
1017 
1018  // 4) for each label, apply ToUnicode
1019  TQStringList::Iterator it;
1020  const TQStringList::Iterator end = input.end();
1021  for (it = input.begin(); it != end; ++it)
1022  {
1023  TQString label = ToUnicode(*it).lower();
1024 
1025  // ToUnicode can't fail
1026  if (!retval.isEmpty())
1027  retval += '.';
1028  retval += label;
1029  }
1030 
1031  return retval;
1032 }
1033 
1034 TQString KResolver::normalizeDomain(const TQString& domain)
1035 {
1036  return domainToUnicode(domainToAscii(domain));
1037 }
1038 
1039 void KResolver::virtual_hook( int, void* )
1040 { /*BASE::virtual_hook( id, data );*/ }
1041 
1042 // here follows IDN functions
1043 // all IDN functions conform to the following documents:
1044 // RFC 3454 - Preparation of Internationalized Strings
1045 // RFC 3490 - Internationalizing Domain Names in Applications (IDNA)
1046 // RFC 3491 - Nameprep: A Stringprep Profile for
1047 // Internationalized Domain Names (IDN
1048 // RFC 3492 - Punycode: A Bootstring encoding of Unicode
1049 // for Internationalized Domain Names in Applications (IDNA)
1050 
1051 static TQStringList splitLabels(const TQString& unicodeDomain)
1052 {
1053  // From RFC 3490 section 3.1:
1054  // "Whenever dots are used as label separators, the following characters
1055  // MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full
1056  // stop), U+FF0E (fullwidth full stop), U+FF61 (halfwidth ideographic full
1057  // stop)."
1058  static const unsigned int separators[] = { 0x002E, 0x3002, 0xFF0E, 0xFF61 };
1059 
1060  TQStringList lst;
1061  int start = 0;
1062  uint i;
1063  for (i = 0; i < unicodeDomain.length(); i++)
1064  {
1065  unsigned int c = unicodeDomain[i].unicode();
1066 
1067  if (c == separators[0] ||
1068  c == separators[1] ||
1069  c == separators[2] ||
1070  c == separators[3])
1071  {
1072  // found a separator!
1073  lst << unicodeDomain.mid(start, i - start);
1074  start = i + 1;
1075  }
1076  }
1077  if ((long)i >= start)
1078  // there is still one left
1079  lst << unicodeDomain.mid(start, i - start);
1080 
1081  return lst;
1082 }
1083 
1084 static TQCString ToASCII(const TQString& label)
1085 {
1086 #ifdef HAVE_IDNA_H
1087  // We have idna.h, so we can use the idna_to_ascii
1088  // function :)
1089 
1090  if (label.length() > 64)
1091  return (char*)0L; // invalid label
1092 
1093  if (label.length() == 0)
1094  // this is allowed
1095  return TQCString(""); // empty, not null
1096 
1097  TQCString retval;
1098  char buf[65];
1099 
1100  TQ_UINT32* ucs4 = new TQ_UINT32[label.length() + 1];
1101 
1102  uint i;
1103  for (i = 0; i < label.length(); i++)
1104  ucs4[i] = (unsigned long)label[i].unicode();
1105  ucs4[i] = 0; // terminate with NUL, just to be on the safe side
1106 
1107  if (idna_to_ascii_4i(ucs4, label.length(), buf, 0) == IDNA_SUCCESS)
1108  // success!
1109  retval = buf;
1110 
1111  delete [] ucs4;
1112  return retval;
1113 #else
1114  return label.latin1();
1115 #endif
1116 }
1117 
1118 static TQString ToUnicode(const TQString& label)
1119 {
1120 #ifdef HAVE_IDNA_H
1121  // We have idna.h, so we can use the idna_to_unicode
1122  // function :)
1123 
1124  TQ_UINT32 *ucs4_input, *ucs4_output;
1125  size_t outlen;
1126 
1127  ucs4_input = new TQ_UINT32[label.length() + 1];
1128  for (uint i = 0; i < label.length(); i++)
1129  ucs4_input[i] = (unsigned long)label[i].unicode();
1130 
1131  // try the same length for output
1132  ucs4_output = new TQ_UINT32[outlen = label.length()];
1133 
1134  idna_to_unicode_44i(ucs4_input, label.length(),
1135  ucs4_output, &outlen,
1136  0);
1137 
1138  if (outlen > label.length())
1139  {
1140  // it must have failed
1141  delete [] ucs4_output;
1142  ucs4_output = new TQ_UINT32[outlen];
1143 
1144  idna_to_unicode_44i(ucs4_input, label.length(),
1145  ucs4_output, &outlen,
1146  0);
1147  }
1148 
1149  // now set the answer
1150  TQString result;
1151  result.setLength(outlen);
1152  for (uint i = 0; i < outlen; i++)
1153  result[i] = (unsigned int)ucs4_output[i];
1154 
1155  delete [] ucs4_input;
1156  delete [] ucs4_output;
1157 
1158  return result;
1159 #else
1160  return label;
1161 #endif
1162 }
1163 
1164 #include "kresolver.moc"

kdecore

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

kdecore

Skip menu "kdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdecore by doxygen 1.8.3.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |