KDELibs4Support

k3resolverstandardworkers.cpp
1 /* -*- C++ -*-
2  * Copyright (C) 2003,2004 Thiago Macieira <[email protected]>
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 "k3resolverstandardworkers_p.h"
26 
27 #include <config-network.h>
28 
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <netinet/in.h>
33 #include <netdb.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 
39 #if HAVE_NET_IF_H
40 #include <net/if.h>
41 #endif
42 
43 #include <QFile>
44 #include <QList>
45 #include <QMutex>
46 #include <QTextStream>
47 #include <QThread>
48 #ifdef Q_OS_WIN
49 #include <winsock2.h>
50 #endif
51 
52 #include "kdebug.h"
53 #include "kglobal.h"
54 #include "kcomponentdata.h"
55 #include "kstandarddirs.h"
56 
57 #include "k3resolver.h"
58 #include "k3socketaddress.h"
59 
60 struct hostent;
61 struct addrinfo;
62 
63 using namespace KNetwork;
64 using namespace KNetwork::Internal;
65 
66 static bool hasIPv6()
67 {
68 #ifdef Q_OS_WIN
69  extern void KNetwork_initSocket();
70  KNetwork_initSocket();
71 #endif
72 #ifdef AF_INET6
73  if (!qgetenv("KDE_NO_IPV6").isEmpty()) {
74  return false;
75  }
76 
77 # ifdef Q_OS_WIN
78  SOCKET s = ::socket(AF_INET6, SOCK_STREAM, 0);
79  if (s == INVALID_SOCKET) {
80  return false;
81  }
82  ::closesocket(s);
83 # else
84  int fd = ::socket(AF_INET6, SOCK_STREAM, 0);
85  if (fd == -1) {
86  return false;
87  }
88  ::close(fd);
89 # endif
90  return true;
91 #else
92  return false;
93 #endif
94 }
95 
96 // blacklist management
97 static QMutex blacklistMutex; // KDE4: change to a QReadWriteLock
98 QStringList KBlacklistWorker::blacklist;
99 
100 void KBlacklistWorker::init()
101 {
103  return;
104  }
105 
106  static bool beenhere = false;
107 
108  if (beenhere) {
109  return;
110  }
111 
112  beenhere = true;
113  loadBlacklist();
114 }
115 
116 void KBlacklistWorker::loadBlacklist()
117 {
118  QMutexLocker locker(&blacklistMutex);
119  QStringList filelist = KGlobal::dirs()->findAllResources("config", QLatin1String("ipv6blacklist"));
120 
121  QStringList::ConstIterator it = filelist.constBegin(),
122  end = filelist.constEnd();
123  for (; it != end; ++it) {
124  // for each file, each line is a domainname to be blacklisted
125  QFile f(*it);
126  if (!f.open(QIODevice::ReadOnly)) {
127  continue;
128  }
129 
130  QTextStream stream(&f);
131  stream.setCodec("latin1");
132  for (QString line = stream.readLine(); !line.isNull();
133  line = stream.readLine()) {
134  if (line.isEmpty()) {
135  continue;
136  }
137 
138  // make sure there are no surrounding whitespaces
139  // and that it starts with .
140  line = line.trimmed();
141  if (line[0] != QLatin1Char('.')) {
142  line.prepend(QLatin1Char('.'));
143  }
144 
145  blacklist.append(line.toLower());
146  }
147  }
148 }
149 
150 // checks the blacklist to see if the domain is listed
151 // it matches the domain ending part
152 bool KBlacklistWorker::isBlacklisted(const QString &host)
153 {
154  KBlacklistWorker::init();
155 
156  // empty hostnames cannot be blacklisted
157  if (host.isEmpty()) {
158  return false;
159  }
160 
162 
163  QMutexLocker locker(&blacklistMutex);
164 
165  // now find out if this hostname is present
166  QStringList::ConstIterator it = blacklist.constBegin(),
167  end = blacklist.constEnd();
168  for (; it != end; ++it)
169  if (ascii.endsWith(*it)) {
170  return true;
171  }
172 
173  // no match:
174  return false;
175 }
176 
177 bool KBlacklistWorker::preprocess()
178 {
179  if (isBlacklisted(nodeName())) {
180  results.setError(KResolver::NoName);
181  finished();
182  return true;
183  }
184  return false;
185 }
186 
187 bool KBlacklistWorker::run()
188 {
189  results.setError(KResolver::NoName);
190  finished();
191  return false; // resolution failure
192 }
193 
194 namespace
195 {
196 /*
197  * Note on the use of the system resolver functions:
198  *
199  * In all cases, we prefer to use the new getaddrinfo(3) call. That means
200  * it will always be used if it is found.
201  *
202  * If it's not found, we have the option to use gethostbyname2_r,
203  * gethostbyname_r, gethostbyname2 and gethostbyname. If gethostbyname2_r
204  * is defined, we will use it.
205  *
206  * If it's not defined, we have to choose between the non-reentrant
207  * gethostbyname2 and the reentrant but IPv4-only gethostbyname_r:
208  * we will choose gethostbyname2 if AF_INET6 is defined.
209  *
210  * Lastly, gethostbyname will be used if nothing else is present.
211  */
212 
213 #if !HAVE_GETADDRINFO
214 
215 # if HAVE_GETHOSTBYNAME2_R
216 # define USE_GETHOSTBYNAME2_R
217 # elif HAVE_GETHOSTBYNAME_R && (!defined(AF_INET6) || !HAVE_GETHOSTBYNAME2)
218 # define USE_GETHOSTBYNAME_R
219 # elif HAVE_GETHOSTBYNAME2
220 # define USE_GETHOSTBYNAME2
221 # else
222 # define USE_GETHOSTBYNAME
223 # endif
224 
225 class GetHostByNameThread: public KResolverWorkerBase
226 {
227 public:
228  QByteArray m_hostname; // might be different!
229  quint16 m_port;
230  int m_scopeid;
231  int m_af;
232  KResolverResults &results;
233 
234  GetHostByNameThread(const char *hostname, quint16 port,
235  int scopeid, int af, KResolverResults *res) :
236  m_hostname(hostname), m_port(port), m_scopeid(scopeid), m_af(af),
237  results(*res)
238  { }
239 
240  ~GetHostByNameThread()
241  { }
242 
243  virtual bool preprocess()
244  {
245  return true;
246  }
247 
248  virtual bool run();
249 
250  void processResults(hostent *he, int my_h_errno);
251 };
252 
253 bool GetHostByNameThread::run()
254 {
255 
256  hostent *resultptr;
257  hostent my_results;
258  unsigned buflen = 1024;
259  int res;
260  int my_h_errno;
261  char *buf = 0L;
262 
263  // qDebug("ResolveThread::run(): started threaded gethostbyname for %s (af = %d)",
264  // m_hostname.data(), m_af);
265 
266  ResolverLocker resLock(this);
267  do {
268  res = 0;
269  my_h_errno = HOST_NOT_FOUND;
270 
271  // check blacklist
272  if (m_af != AF_INET &&
273  KBlacklistWorker::isBlacklisted(QLatin1String(m_hostname))) {
274  break;
275  }
276 
277 # ifdef USE_GETHOSTBYNAME2_R
278  buf = new char[buflen];
279  res = gethostbyname2_r(m_hostname, m_af, &my_results, buf, buflen,
280  &resultptr, &my_h_errno);
281 
282 # elif defined(USE_GETHOSTBYNAME_R)
283  if (m_af == AF_INET) {
284  buf = new char[buflen];
285  res = gethostbyname_r(m_hostname, &my_results, buf, buflen,
286  &resultptr, &my_h_errno);
287  } else {
288  resultptr = 0; // signal error
289  }
290 
291 # elif defined(USE_GETHOSTBYNAME2)
292  // must lock mutex
293  resultptr = gethostbyname2(m_hostname, m_af);
294  my_h_errno = h_errno;
295 
296 # else
297  if (m_af == AF_INET) {
298  // must lock mutex
299  resultptr = gethostbyname(m_hostname);
300  my_h_errno = h_errno;
301  } else {
302  resultptr = 0;
303  }
304 # endif
305 
306  if (resultptr != 0L) {
307  my_h_errno = 0;
308  }
309  // qDebug("GetHostByNameThread::run(): gethostbyname for %s (af = %d) returned: %d",
310  // m_hostname.data(), m_af, my_h_errno);
311 
312  if (res == ERANGE) {
313  // Enlarge the buffer
314  buflen += 1024;
315  delete [] buf;
316  buf = new char[buflen];
317  }
318 
319  if ((res == ERANGE || my_h_errno != 0) && checkResolver()) {
320  // resolver needs updating, so we might as well do it now
321  resLock.openClose();
322  }
323  } while (res == ERANGE);
324  processResults(resultptr, my_h_errno);
325 
326  delete [] buf;
327 
328  finished();
329  return results.error() == KResolver::NoError;
330 }
331 
332 void GetHostByNameThread::processResults(hostent *he, int herrno)
333 {
334  if (herrno) {
335  qDebug("KStandardWorker::processResults: got error %d", herrno);
336  switch (herrno) {
337  case HOST_NOT_FOUND:
338  results.setError(KResolver::NoName);
339  return;
340 
341  case TRY_AGAIN:
342  results.setError(KResolver::TryAgain);
343  return;
344 
345  case NO_RECOVERY:
346  results.setError(KResolver::NonRecoverable);
347  return;
348 
349  case NO_ADDRESS:
350  results.setError(KResolver::NoName);
351  return;
352 
353  default:
354  results.setError(KResolver::UnknownError);
355  return;
356  }
357  } else if (he == 0L) {
358  results.setError(KResolver::NoName);
359  return; // this was an error
360  }
361 
362  // clear any errors
363  setError(KResolver::NoError);
364  results.setError(KResolver::NoError);
365 
366  // we process results in the reverse order
367  // that is, we prepend each result to the list of results
368  int proto = protocol();
369  int socktype = socketType();
370  if (socktype == 0) {
371  socktype = SOCK_STREAM; // default
372  }
373 
374  QString canon = KResolver::domainToUnicode(QLatin1String(he->h_name));
376  sa.setPort(m_port);
377  if (he->h_addrtype != AF_INET) {
378  sa.setScopeId(m_scopeid); // this will also change the socket into IPv6
379  }
380 
381  for (int i = 0; he->h_addr_list[i]; i++) {
382  sa.setHost(KIpAddress(he->h_addr_list[i], he->h_addrtype == AF_INET ? 4 : 6));
383  results.prepend(KResolverEntry(sa, socktype, proto, canon, m_hostname));
384  // qDebug("KStandardWorker::processResults: adding %s", sa.toString().toLatin1().constData());
385  }
386  // qDebug("KStandardWorker::processResults: added %d entries", i);
387 }
388 
389 #else // HAVE_GETADDRINFO
390 
391 class GetAddrInfoThread: public KResolverWorkerBase
392 {
393 public:
394  QByteArray m_node;
395  QByteArray m_serv;
396  int m_af;
397  int m_flags;
398  KResolverResults &results;
399 
400  GetAddrInfoThread(const char *node, const char *serv, int af, int flags,
401  KResolverResults *res) :
402  m_node(node), m_serv(serv), m_af(af), m_flags(flags), results(*res)
403  { }
404 
405  ~GetAddrInfoThread()
406  { }
407 
408  bool preprocess() override
409  {
410  return true;
411  }
412 
413  bool run() override;
414 
415  void processResults(addrinfo *ai, int ret_code, KResolverResults &rr);
416 };
417 
418 bool GetAddrInfoThread::run()
419 {
420  // check blacklist
421  if ((m_af != AF_INET && m_af != AF_UNSPEC) &&
422  KBlacklistWorker::isBlacklisted(QLatin1String(m_node))) {
423  results.setError(KResolver::NoName);
424  finished();
425  return false; // failed
426  }
427 
428  do {
429  ResolverLocker resLock(this);
430 
431  // process hints
432  addrinfo hint;
433  memset(&hint, 0, sizeof(hint));
434  hint.ai_family = m_af;
435  hint.ai_socktype = socketType();
436  hint.ai_protocol = protocol();
437 
438  if (hint.ai_socktype == 0) {
439  hint.ai_socktype = SOCK_STREAM; // default
440  }
441 
442  if (m_flags & KResolver::Passive) {
443  hint.ai_flags |= AI_PASSIVE;
444  }
445  if (m_flags & KResolver::CanonName) {
446  hint.ai_flags |= AI_CANONNAME;
447  }
448 # ifdef AI_NUMERICHOST
449  if (m_flags & KResolver::NoResolve) {
450  hint.ai_flags |= AI_NUMERICHOST;
451  }
452 # endif
453 # ifdef AI_ADDRCONFIG
454  hint.ai_flags |= AI_ADDRCONFIG;
455 # endif
456 
457  // now we do the blocking processing
458  if (m_node.isEmpty()) {
459  m_node = "*"; // krazy:exclude=doublequote_chars
460  }
461 
462  addrinfo *result;
463  int res = getaddrinfo(m_node, m_serv, &hint, &result);
464  // kDebug(179) << "getaddrinfo(\""
465  // << m_node << "\", \"" << m_serv << "\", af="
466  // << m_af << ") returned " << res << endl;
467 
468  if (res != 0) {
469  if (checkResolver()) {
470  // resolver requires reinitialisation
471  resLock.openClose();
472  continue;
473  }
474 
475  switch (res) {
476  case EAI_BADFLAGS:
477  results.setError(KResolver::BadFlags);
478  break;
479 
480 #ifdef EAI_NODATA
481  // In some systems, EAI_NODATA was #define'd to EAI_NONAME which would break this case.
482 #if EAI_NODATA != EAI_NONAME
483  case EAI_NODATA: // it was removed in RFC 3493
484 #endif
485 #endif
486  case EAI_NONAME:
487  results.setError(KResolver::NoName);
488  break;
489 
490  case EAI_AGAIN:
491  results.setError(KResolver::TryAgain);
492  break;
493 
494  case EAI_FAIL:
495  results.setError(KResolver::NonRecoverable);
496  break;
497 
498  case EAI_FAMILY:
499  results.setError(KResolver::UnsupportedFamily);
500  break;
501 
502  case EAI_SOCKTYPE:
503  results.setError(KResolver::UnsupportedSocketType);
504  break;
505 
506  case EAI_SERVICE:
507  results.setError(KResolver::UnsupportedService);
508  break;
509 
510  case EAI_MEMORY:
511  results.setError(KResolver::Memory);
512  break;
513 
514 #ifdef EAI_SYSTEM // not available on windows
515  case EAI_SYSTEM:
516  results.setError(KResolver::SystemError, errno);
517  break;
518 #endif
519  default:
520  results.setError(KResolver::UnknownError, errno);
521  break;
522  }
523 
524  finished();
525  return false; // failed
526  }
527 
528  // if we are here, lookup succeeded
529  QString canon;
530  const char *previous_canon = nullptr;
531 
532  for (addrinfo *p = result; p; p = p->ai_next) {
533  // cache the last canon name to avoid doing the ToUnicode processing unnecessarily
534  if ((previous_canon && !p->ai_canonname) ||
535  (!previous_canon && p->ai_canonname) ||
536  (p->ai_canonname != previous_canon &&
537  strcmp(p->ai_canonname, previous_canon) != 0)) {
538  canon = KResolver::domainToUnicode(QString::fromLatin1(p->ai_canonname));
539  previous_canon = p->ai_canonname;
540  }
541 
542  results.append(KResolverEntry(p->ai_addr, p->ai_addrlen, p->ai_socktype,
543  p->ai_protocol, canon, m_node));
544  }
545 
546  freeaddrinfo(result);
547  results.setError(KResolver::NoError);
548  finished();
549  return results.error() == KResolver::NoError;
550  } while (true);
551 }
552 
553 #endif // HAVE_GETADDRINFO
554 } // namespace
555 
556 KStandardWorker::~KStandardWorker()
557 {
558  qDeleteAll(resultList);
559 }
560 
561 bool KStandardWorker::sanityCheck()
562 {
563  // check that the requested values are sensible
564 
565  if (!nodeName().isEmpty()) {
566  QString node = nodeName();
567  if (node.indexOf(QLatin1Char('%')) != -1) {
568  node.truncate(node.indexOf(QLatin1Char('%')));
569  }
570 
571  if (node.isEmpty() || node == QLatin1String("*") ||
572  node == QLatin1String("localhost")) {
573  m_encodedName.truncate(0);
574  } else {
575  m_encodedName = KResolver::domainToAscii(node);
576 
577  if (m_encodedName.isNull()) {
578  qDebug("could not encode hostname '%s' (UTF-8)", node.toUtf8().data());
579  setError(KResolver::NoName);
580  return false; // invalid hostname!
581  }
582 
583  // qDebug("Using encoded hostname '%s' for '%s' (UTF-8)", m_encodedName.data(),
584  // node.toUtf8().data());
585  }
586  } else {
587  m_encodedName.truncate(0); // just to be sure, but it should be clear already
588  }
589 
590  if (protocol() == -1) {
591  setError(KResolver::NonRecoverable);
592  return false; // user passed invalid protocol name
593  }
594 
595  return true; // it's sane
596 }
597 
598 bool KStandardWorker::resolveScopeId()
599 {
600  // we must test the original name, not the encoded one
601  scopeid = 0;
602  int pos = nodeName().lastIndexOf(QLatin1Char('%'));
603  if (pos == -1) {
604  return true;
605  }
606 
607  QString scopename = nodeName().mid(pos + 1);
608 
609  bool ok;
610  scopeid = scopename.toInt(&ok);
611  if (!ok) {
612  // it's not a number
613  // therefore, it's an interface name
614 #if HAVE_IF_NAMETOINDEX
615  scopeid = if_nametoindex(scopename.toLatin1());
616 #else
617  scopeid = 0;
618 #endif
619  }
620 
621  return true;
622 }
623 
624 bool KStandardWorker::resolveService()
625 {
626  // find the service first
627  bool ok;
628  port = serviceName().toUInt(&ok);
629  if (!ok) {
630  // service name does not contain a port number
631  // must be a name
632 
633  if (serviceName().isEmpty() || serviceName().compare(QLatin1String("*")) == 0) {
634  port = 0;
635  } else {
636  // it's a name. We need the protocol name in order to lookup.
637  QByteArray protoname = protocolName();
638 
639  if (protoname.isEmpty() && protocol()) {
640  protoname = KResolver::protocolName(protocol()).first();
641 
642  // if it's still empty...
643  if (protoname.isEmpty()) {
644  // lookup failed!
645  setError(KResolver::NoName);
646  return false;
647  }
648  } else {
649  protoname = "tcp";
650  }
651 
652  // it's not, so we can do a port lookup
653  int result = KResolver::servicePort(serviceName().toLatin1(), protoname);
654  if (result == -1) {
655  // lookup failed!
656  setError(KResolver::NoName);
657  return false;
658  }
659 
660  // it worked, we have a port number
661  port = (quint16)result;
662  }
663  }
664 
665  // we found a port
666  return true;
667 }
668 
669 KResolver::ErrorCodes KStandardWorker::addUnix()
670 {
671  // before trying to add, see if the user wants Unix sockets
672  if ((familyMask() & KResolver::UnixFamily) == 0)
673  // no, Unix sockets are not wanted
674  {
675  return KResolver::UnsupportedFamily;
676  }
677 
678  // now check if the requested data are good for a Unix socket
679  if (!m_encodedName.isEmpty()) {
680  return KResolver::AddrFamily; // non local hostname
681  }
682 
683  if (protocol() || !protocolName().isNull()) {
684  return KResolver::BadFlags; // cannot have Unix sockets with protocols
685  }
686 
687  QString pathname = serviceName();
688  if (pathname.isEmpty()) {
689  return KResolver::NoName;
690  }; // no path?
691 
692  if (pathname[0] != QLatin1Char('/'))
693  // non absolute pathname
694  // put it in /tmp
695  {
696  pathname.prepend(QLatin1String("/tmp/"));
697  }
698 
699  // qDebug("QNoResolveWorker::addUnix(): adding Unix socket for %s", pathname.toLocal8Bit().data());
700  KUnixSocketAddress sa(pathname);
701  int socktype = socketType();
702  if (socktype == 0) {
703  socktype = SOCK_STREAM; // default
704  }
705 
706  results.append(KResolverEntry(sa, socktype, 0));
707  setError(KResolver::NoError);
708 
709  return KResolver::NoError;
710 }
711 
712 bool KStandardWorker::resolveNumerically()
713 {
714  // if the NoResolve flag is active, our result from this point forward
715  // will always be true, even if the resolution failed.
716  // that indicates that our result is authoritative.
717 
718  bool wantV4 = familyMask() & KResolver::IPv4Family,
719  wantV6 = familyMask() & KResolver::IPv6Family;
720 
721  if (!wantV6 && !wantV4)
722  // no Internet address is wanted!
723  {
724  return (flags() & KResolver::NoResolve);
725  }
726 
727  // now try to find results
728  if (!resolveScopeId() || !resolveService()) {
729  return (flags() & KResolver::NoResolve);
730  }
731 
732  // we have scope IDs and port numbers
733  // now try to resolve the hostname numerically
735  setError(KResolver::NoError);
736  sa.setHost(KIpAddress(QLatin1String(m_encodedName)));
737 
738  // if it failed, the length was reset to 0
739  bool ok = sa.length() != 0;
740 
741  sa.setPort(port);
742  if (sa.ipVersion() == 6) {
743  sa.setScopeId(scopeid);
744  }
745  int proto = protocol();
746  int socktype = socketType();
747  if (socktype == 0) {
748  socktype = SOCK_STREAM;
749  }
750 
751  if (ok) {
752  // the given hostname was successfully converted to an IP address
753  // check if the user wanted this kind of address
754 
755  if ((sa.ipVersion() == 4 && wantV4) ||
756  (sa.ipVersion() == 6 && wantV6)) {
757  results.append(KResolverEntry(sa, socktype, proto));
758  } else {
759  // Note: the address *IS* a numeric IP
760  // but it's not of the kind the user asked for
761  //
762  // that means that it cannot be a Unix socket (because it's an IP)
763  // and that means that no resolution will tell us otherwise
764  //
765  // This is a failed resolution
766 
767  setError(KResolver::AddrFamily);
768  return true;
769  }
770  } else if (m_encodedName.isEmpty()) {
771  // user wanted localhost
772  if (flags() & KResolver::Passive) {
773  if (wantV6) {
775  results.append(KResolverEntry(sa, socktype, proto));
776  }
777 
778  if (wantV4) {
780  results.append(KResolverEntry(sa, socktype, proto));
781  }
782  } else {
783  if (wantV6) {
785  results.append(KResolverEntry(sa, socktype, proto));
786  }
787 
788  if (wantV4) {
790  results.append(KResolverEntry(sa, socktype, proto));
791  }
792  }
793 
794  ok = true;
795  } else {
796  // probably bad flags, since the address is not convertible without
797  // resolution
798 
799  setError(KResolver::BadFlags);
800  ok = false;
801  }
802 
803  return ok || (flags() & KResolver::NoResolve);
804 }
805 
806 bool KStandardWorker::preprocess()
807 {
808  // check sanity
809  if (!sanityCheck()) {
810  return false;
811  }
812 
813  // this worker class can only handle known families
814  if (familyMask() & KResolver::UnknownFamily) {
815  setError(KResolver::UnsupportedFamily);
816  return false; // we don't know about this
817  }
818 
819  // check the socket types
820  if (socketType() != SOCK_STREAM && socketType() != SOCK_DGRAM && socketType() != 0) {
821  setError(KResolver::UnsupportedSocketType);
822  return false;
823  }
824 
825  // check if we can resolve all numerically
826  // resolveNumerically always returns true if the NoResolve flag is set
827  if (resolveNumerically() || m_encodedName.isEmpty()) {
828  // indeed, we have resolved numerically
829  setError(addUnix());
830  if (results.count()) {
831  setError(KResolver::NoError);
832  }
833  finished();
834  return true;
835  }
836 
837  // check if the user wants something we know about
838 #ifdef AF_INET6
839 # define mask (KResolver::IPv6Family | KResolver::IPv4Family | KResolver::UnixFamily)
840 #else
841 # define mask (KResolver::IPv4Family | KResolver::UnixFamily)
842 #endif
843 
844  if ((familyMask() & mask) == 0)
845  // errr... nothing we know about
846  {
847  return false;
848  }
849 
850 #undef mask
851 
852  return true; // it's ok
853 }
854 
855 bool KStandardWorker::run()
856 {
857 #if !HAVE_GETADDRINFO
858  // check the scope id first
859  // since most of the resolutions won't have a scope id, this should be fast
860  // and we won't have wasted time on services if this fails
861  if (!resolveScopeId()) {
862  return false;
863  }
864 
865  // resolve the service now, before entering the blocking operation
866  if (!resolveService()) {
867  return false;
868  }
869 #endif
870 
871  // good
872  // now we need the hostname
873  setError(KResolver::NoName);
874 
875  // these are the family types that we know of
876  struct {
878  int af;
879  } families[] = { { KResolver::IPv4Family, AF_INET }
880 #ifdef AF_INET6
881  , { KResolver::IPv6Family, AF_INET6 }
882 #endif
883  };
884  int familyCount = sizeof(families) / sizeof(families[0]);
885  bool skipIPv6 = !hasIPv6();
886 
887  for (int i = 0; i < familyCount; i++)
888  if (familyMask() & families[i].mask) {
889 #ifdef AF_INET6
890  if (skipIPv6 && families[i].af == AF_INET6) {
891  continue;
892  }
893 #endif
894 
895  KResolverWorkerBase *worker;
897  resultList.append(res);
898 #if HAVE_GETADDRINFO
899  worker = new GetAddrInfoThread(m_encodedName,
900  serviceName().toLatin1(),
901  families[i].af, flags(), res);
902 #else
903  worker = new GetHostByNameThread(m_encodedName, port, scopeid,
904  families[i].af, res);
905 #endif
906 
907  enqueue(worker);
908  }
909 
910  // not finished
911  return true;
912 }
913 
914 bool KStandardWorker::postprocess()
915 {
916  if (results.count()) {
917  return true; // no need
918  }
919  // now copy over what we need from the underlying results
920 
921  // start backwards because IPv6 was launched later (if at all)
922  if (resultList.isEmpty()) {
923  results.setError(KResolver::NoName);
924  return true;
925  }
926 
927  for (int i = resultList.size(); i > 0; --i) {
928  KResolverResults *rr = resultList.at(i - 1);
929  if (!rr->isEmpty()) {
930  results.setError(KResolver::NoError);
932  for (; it != rr->end(); ++it) {
933  results.append(*it);
934  }
935  } else if (results.isEmpty())
936  // this generated an error
937  // copy the error code over
938  {
939  setError(rr->error(), rr->systemError());
940  }
941 
942  delete rr;
943  resultList[i - 1] = nullptr;
944  }
945 
946  resultList.clear();
947  return true;
948 }
949 
950 #if HAVE_GETADDRINFO
951 KGetAddrinfoWorker::~KGetAddrinfoWorker()
952 {
953 }
954 
955 bool KGetAddrinfoWorker::preprocess()
956 {
957  // getaddrinfo(3) can always handle any kind of request that makes sense
958  if (!sanityCheck()) {
959  return false;
960  }
961 
962  if (flags() & KResolver::NoResolve)
963  // oops, numeric resolution?
964  {
965  return run();
966  }
967 
968  return true;
969 }
970 
971 bool KGetAddrinfoWorker::run()
972 {
973  // make an AF_UNSPEC getaddrinfo(3) call
974  GetAddrInfoThread worker(m_encodedName, serviceName().toLatin1(),
975  AF_UNSPEC, flags(), &results);
976 
977  if (!worker.run()) {
978  if (wantThis(AF_UNIX)) {
979  if (addUnix() == KResolver::NoError) {
980  setError(KResolver::NoError);
981  }
982  } else {
983  setError(worker.results.error(), worker.results.systemError());
984  }
985 
986  return false;
987  }
988 
989  // The worker has finished working
990  // now copy over only what we may want
991  // keep track of any Unix-domain sockets
992 
993  bool seen_unix = false;
994  int i = 0;
995  while (i < results.count()) {
996  const KResolverEntry &res = results[i];
997  if (res.family() == AF_UNIX) {
998  seen_unix = true;
999  }
1000  if (!wantThis(res.family())) {
1001  results.removeAt(i);
1002  } else {
1003  ++i;
1004  }
1005  }
1006 
1007  if (!seen_unix) {
1008  addUnix();
1009  }
1010 
1011  finished();
1012  return true;
1013 }
1014 
1015 bool KGetAddrinfoWorker::wantThis(int family)
1016 {
1017  // tells us if the user wants a socket of this family
1018 
1019 #ifdef AF_INET6
1020  if (family == AF_INET6 && familyMask() & KResolver::IPv6Family) {
1021  return true;
1022  }
1023 #endif
1024  if (family == AF_INET && familyMask() & KResolver::IPv4Family) {
1025  return true;
1026  }
1027  if (family == AF_UNIX && familyMask() & KResolver::UnixFamily) {
1028  return true;
1029  }
1030 
1031  // it's not a family we know about...
1032  if (familyMask() & KResolver::UnknownFamily) {
1033  return true;
1034  }
1035 
1036  return false;
1037 }
1038 
1039 #endif
1040 
1041 void KNetwork::Internal::initStandardWorkers()
1042 {
1043  //KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KBlacklistWorker>);
1045 
1046 #if HAVE_GETADDRINFO
1048 #endif
1049 }
static const KIpAddress anyhostV6
the any host or undefined address in IPv6 (::)
A Unix (local) socket address.
void clear()
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
an Internet socket address
void truncate(int position)
An IP address.
ErrorCodes
Error codes.
Definition: k3resolver.h:395
One resolution entry.
Definition: k3resolver.h:72
QString & prepend(QChar ch)
const T & at(int i) const const
void removeAt(int i)
bool isEmpty() const const
KResolverResults results
Derived classes will put their resolved data in this list, or will leave it empty in case of error...
bool isNull() const const
Name and service resolution results.
Definition: k3resolver.h:212
bool isNull() const const
A namespace to store all networking-related (socket) classes.
static const KIpAddress localhostV4
localhost in IPv4 (127.0.0.1)
void append(const T &value)
KInetSocketAddress & setPort(quint16 port)
Sets the port number.
int toInt(bool *ok, int base) const const
bool isEmpty() const const
int systemError() const
Retrieves the system error code, if any.
Definition: k3resolver.cpp:233
bool isEmpty() const const
int ipVersion() const
Returns the IP version of the address this object holds.
static bool hasMainComponent()
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
T & first()
static const KIpAddress anyhostV4
the any host or undefined address in IPv4 (0.0.0.0)
KDEGAMES_EXPORT QAction * hint(const QObject *recvr, const char *slot, QObject *parent)
KInetSocketAddress & setScopeId(int scopeid)
Sets the scope id for this IPv6 object.
virtual bool run()=0
This is the function that should be overridden in derived classes.
static QList< QByteArray > protocolName(int protonum)
Resolves a protocol number to its names.
Definition: k3resolver.cpp:600
QList::iterator end()
KInetSocketAddress & setHost(const KIpAddress &addr)
Sets the IP address to the given raw address.
const QList< QKeySequence > & end()
QByteArray toLatin1() const const
QString mid(int position, int n) const const
KIOWIDGETS_EXPORT bool run(const QUrl &_url, bool _is_local)
static QString domainToUnicode(const QByteArray &asciiDomain)
Does the inverse of domainToAscii() and return an Unicode domain name from the given ACE-encoded doma...
quint16 length() const
Returns the length of this socket address structure.
typedef ConstIterator
int family() const
Retrieves the family associated with this socket address.
Definition: k3resolver.cpp:145
static int servicePort(const char *servname, const char *protoname)
Resolves a service name to its port number.
Definition: k3resolver.cpp:775
char * data()
QString fromLatin1(const char *str, int size)
QStringList findAllResources(const char *type, const QString &filter=QString(), SearchOptions options=NoSearchOptions) const
Tries to find all resources with the specified type.
QList::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
static void registerNewWorker(KResolverWorkerFactoryBase *factory)
Wrapper call to register workers.
int error() const
Retrieves the error code associated with this resolution.
Definition: k3resolver.cpp:227
SocketFamilies
Address family selection types.
Definition: k3resolver.h:334
QLatin1String KPIMKDAV2_EXPORT protocolName(Protocol protocol)
QList::iterator begin()
static const KIpAddress localhostV6
localhost in IPv6 (::1)
static QByteArray domainToAscii(const QString &unicodeDomain)
Returns the domain name in an ASCII Compatible Encoding form, suitable for DNS lookups.
KStandardDirs * dirs()
Returns the application standard dirs object.
Definition: kglobal.cpp:91
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jul 3 2020 22:57:52 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.