• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.4 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • network
netsupp.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 2000,2001 Thiago Macieira <thiago.macieira@kdemail.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  **/
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <netinet/in.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <arpa/inet.h>
30 
31 #include <QtCore/QBool>
32 
33 #include <kdebug.h>
34 
35 // This is so that, if addrinfo is defined, it doesn't clobber our definition
36 // It might be defined in the few cases in which we are replacing the system's
37 // broken getaddrinfo
38 #include <netdb.h>
39 
40 #include <config.h>
41 #include <config-network.h>
42 #include "klocale.h"
43 
44 #ifndef IN6_IS_ADDR_V4MAPPED
45 #define NEED_IN6_TESTS
46 #endif
47 #undef CLOBBER_IN6
48 #include "netsupp.h" //krazy:exclude=includes (netsupp.h not installed; KDE3 compat code)
49 
50 #if defined(__hpux) || defined(_HPUX_SOURCE)
51 extern int h_errno;
52 #endif
53 
54 #if !defined(kde_sockaddr_in6)
55 /*
56  * kde_sockaddr_in6 might have got defined even though we #undef'ed
57  * CLOBBER_IN6. This happens when we are compiling under --enable-final.
58  * However, in that case, if it was defined, that's because ksockaddr.cpp
59  * had it defined because sockaddr_in6 didn't exist, and so sockaddr_in6
60  * exists and is our kde_sockaddr_in6
61  */
62 # define sockaddr_in6 kde_sockaddr_in6
63 # define in6_addr kde_in6_addr
64 #endif
65 
66 #ifdef offsetof
67 #undef offsetof
68 #endif
69 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
70 
71 /*
72  * These constants tell the flags in KDE::resolverFlags
73  * The user could (but shouldn't) test the variable to know what kind of
74  * resolution is supported
75  */
76 #define KRF_KNOWS_AF_INET6 0x01 /* if present, the code knows about AF_INET6 */
77 #define KRF_USING_OWN_GETADDRINFO 0x02 /* if present, we are using our own getaddrinfo */
78 #define KRF_USING_OWN_INET_NTOP 0x04 /* if present, we are using our own inet_ntop */
79 #define KRF_USING_OWN_INET_PTON 0x08 /* if present, we are using our own inet_pton */
80 #define KRF_CAN_RESOLVE_UNIX 0x100 /* if present, the resolver can resolve Unix sockets */
81 #define KRF_CAN_RESOLVE_IPV4 0x200 /* if present, the resolver can resolve to IPv4 */
82 #define KRF_CAN_RESOLVE_IPV6 0x400 /* if present, the resolver can resolve to IPv6 */
83 
84 
85 static void dofreeaddrinfo(struct addrinfo *ai)
86 {
87  while (ai)
88  {
89  struct addrinfo *ai2 = ai;
90  if (ai->ai_canonname != NULL)
91  free(ai->ai_canonname);
92 
93  if (ai->ai_addr != NULL)
94  free(ai->ai_addr);
95 
96  ai = ai->ai_next;
97  free(ai2);
98  }
99 }
100 
101 void kde_freeaddrinfo(struct kde_addrinfo *ai)
102 {
103  if (ai->origin == KAI_LOCALUNIX)
104  {
105  struct addrinfo *p, *last = NULL;
106  /* We've added one AF_UNIX socket in here, to the
107  * tail of the linked list. We have to find it */
108  for (p = ai->data; p; p = p->ai_next)
109  {
110  if (p->ai_family == AF_UNIX)
111  {
112  if (last)
113  {
114  last->ai_next = NULL;
115  freeaddrinfo(ai->data);
116  }
117  dofreeaddrinfo(p);
118  break;
119  }
120  last = p;
121  }
122  }
123  else
124  freeaddrinfo(ai->data);
125 
126  free(ai);
127 }
128 
129 static struct addrinfo*
130 make_unix(const char *name, const char *serv)
131 {
132  const char *buf;
133  struct addrinfo *p;
134  struct sockaddr_un *_sun;
135  int len;
136 
137  p = (addrinfo*)malloc(sizeof(*p));
138  if (p == NULL)
139  return NULL;
140  memset(p, 0, sizeof(*p));
141 
142  if (name != NULL)
143  buf = name;
144  else
145  buf = serv;
146 
147  // Calculate length of the binary representation
148  len = strlen(buf) + offsetof(struct sockaddr_un, sun_path) + 1;
149  if (*buf != '/')
150  len += 5; // strlen("/tmp/");
151 
152  _sun = (sockaddr_un*)malloc(len);
153  if (_sun == NULL)
154  {
155  // Oops
156  free(p);
157  return NULL;
158  }
159 
160  _sun->sun_family = AF_UNIX;
161 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
162  _sun->sun_len = len;
163 # endif
164  if (*buf == '/')
165  *_sun->sun_path = '\0'; // empty it
166  else
167  strcpy(_sun->sun_path, "/tmp/");
168  strcat(_sun->sun_path, buf);
169 
170  // Set the addrinfo
171  p->ai_family = AF_UNIX;
172  p->ai_addrlen = len;
173  p->ai_addr = (sockaddr*)_sun;
174  p->ai_canonname = qstrdup(buf);
175 
176  return p;
177 }
178 
179 // Ugh. I hate #ifdefs
180 // Anyways, here's what this does:
181 // KDE_IPV6_LOOKUP_MODE != 1, this function doesn't exist
182 // AF_INET6 not defined, we say there is no IPv6 stack
183 // otherwise, we try to create a socket.
184 // returns: 1 for IPv6 stack available, 2 for not available
185 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1
186 static int check_ipv6_stack()
187 {
188 # ifndef AF_INET6
189  return 2; // how can we check?
190 # else
191  if (!qgetenv("KDE_NO_IPV6").isEmpty())
192  return 2;
193  int fd = ::socket(AF_INET6, SOCK_STREAM, 0);
194  if (fd == -1)
195  return 2;
196 
197  ::close(fd);
198  return 1;
199 # endif
200 }
201 #endif
202 
203 
204 /*
205  * Reason for using this function: kde_getaddrinfo
206  *
207  * I decided to add this wrapper function for getaddrinfo
208  * and have this be called by KExtendedSocket instead of
209  * the real getaddrinfo so that we can make sure that the
210  * behavior is the desired one.
211  *
212  * Currently, the only "undesired" behavior is getaddrinfo
213  * not returning PF_UNIX sockets in some implementations.
214  *
215  * getaddrinfo and family are defined in POSIX 1003.1g
216  * (Protocol Independent Interfaces) and in RFC 2553
217  * (Basic Socket Interface for IPv6). Whereas the RFC is ambiguosly
218  * vague whether this family of functions should return Internet
219  * sockets only or not, the name of the POSIX draft says
220  * otherwise: it should be independent of protocol.
221  *
222  * So, my interpretation is that they should return every
223  * kind of socket available and known and that's how I
224  * designed KExtendedSocket on top of it.
225  *
226  * That's why there's this wrapper, to make sure PF_UNIX
227  * sockets are returned when expected.
228  */
229 
230 int kde_getaddrinfo(const char *name, const char *service,
231  const struct addrinfo* hint,
232  struct kde_addrinfo** result)
233 {
234  struct kde_addrinfo* res;
235  struct addrinfo* p;
236  int err = EAI_SERVICE;
237 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1
238  // mode 1: do a check on whether we have an IPv6 stack
239  static int ipv6_stack = 0; // 0: unknown, 1: yes, 2: no
240 #endif
241 
242  // allocate memory for results
243  res = (kde_addrinfo*)malloc(sizeof(*res));
244  if (res == NULL)
245  return EAI_MEMORY;
246  res->data = NULL;
247  res->origin = KAI_SYSTEM; // at first, it'll be only system data
248 
249  struct addrinfo* last = NULL;
250 
251  // Skip the getaddrinfo call and the ipv6 check for a UNIX socket.
252  if (hint && (hint->ai_family == PF_UNIX))
253  {
254  if (service == NULL || *service == '\0')
255  goto out; // can't be Unix if no service was requested
256 
257  // Unix sockets must be localhost
258  // That is, either name is NULL or, if it's not, it must be empty,
259  // "*" or "localhost"
260  if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') ||
261  strcmp("localhost", name) == 0))
262  goto out; // isn't localhost
263 
264  goto do_unix;
265  }
266 
267 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE != 0
268 # if KDE_IPV6_LOOKUP_MODE == 1
269  // mode 1: do a check on whether we have an IPv6 stack
270  if (ipv6_stack == 0)
271  ipv6_stack = check_ipv6_stack();
272 
273  if (ipv6_stack == 2)
274  {
275 # endif
276  // here we have modes 1 and 2 (no lookups)
277  // this is shared code
278  struct addrinfo our_hint;
279  if (hint != NULL)
280  {
281  memcpy(&our_hint, hint, sizeof(our_hint));
282  if (our_hint.ai_family == AF_UNSPEC)
283  our_hint.ai_family = AF_INET;
284  }
285  else
286  {
287  memset(&our_hint, 0, sizeof(our_hint));
288  our_hint.ai_family = AF_INET;
289  }
290 
291  // do the actual resolution
292  err = getaddrinfo(name, service, &our_hint, &res->data);
293 # if KDE_IPV6_LOOKUP_MODE == 1
294  }
295  else
296 # endif
297 #endif
298 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE != 2
299  // do the IPV6 resolution
300  err = getaddrinfo(name, service, hint, &res->data);
301 #endif
302 
303  // Now we have to check whether the user could want a Unix socket
304 
305  if (service == NULL || *service == '\0')
306  goto out; // can't be Unix if no service was requested
307 
308  // Unix sockets must be localhost
309  // That is, either name is NULL or, if it's not, it must be empty,
310  // "*" or "localhost"
311  if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') ||
312  strcmp("localhost", name) == 0))
313  goto out; // isn't localhost
314 
315  // Unix sockets can only be returned if the user asked for a PF_UNSPEC
316  // or PF_UNIX socket type or gave us a NULL hint
317  if (hint != NULL && (hint->ai_family != PF_UNSPEC && hint->ai_family != PF_UNIX))
318  goto out; // user doesn't want Unix
319 
320  // If we got here, then it means that the user might be expecting Unix
321  // sockets. The user wants a local socket, with a non-null service and
322  // has told us that they accept PF_UNIX sockets
323  // Check whether the system implementation returned Unix
324  if (err == 0)
325  for (p = res->data; p; p = p->ai_next)
326  {
327  last = p; // we have to find out which one is last anyways
328  if (p->ai_family == AF_UNIX)
329  // there is an Unix node
330  goto out;
331  }
332 
333  do_unix:
334  // So, give the user a PF_UNIX socket
335  p = make_unix(NULL, service);
336  if (p == NULL)
337  {
338  err = EAI_MEMORY;
339  goto out;
340  }
341  if (hint != NULL)
342  p->ai_socktype = hint->ai_socktype;
343  if (p->ai_socktype == 0)
344  p->ai_socktype = SOCK_STREAM; // default
345 
346  if (last)
347  last->ai_next = p;
348  else
349  res->data = p;
350  res->origin = KAI_LOCALUNIX;
351  *result = res;
352  return 0;
353 
354  out:
355  if (res->data != NULL)
356  freeaddrinfo(res->data);
357  free(res);
358  return err;
359 }
360 
361 #if defined(HAVE_GETADDRINFO) && !defined(HAVE_BROKEN_GETADDRINFO)
362 
363 #define KRF_getaddrinfo 0
364 #define KRF_resolver 0
365 
366 #else // !defined(HAVE_GETADDRINFO) || defined(HAVE_BROKEN_GETADDRINFO)
367 
368 #define KRF_getaddrinfo KRF_USING_OWN_GETADDRINFO
369 #define KRF_resolver KRF_CAN_RESOLVE_UNIX | KRF_CAN_RESOLVE_IPV4
370 
371 /*
372  * No getaddrinfo() in this system.
373  * We shall provide our own
374  */
375 
379 static int inet_lookup(const char *name, int portnum, int protonum,
380  struct addrinfo *p, const struct addrinfo *hint,
381  struct addrinfo** result)
382 {
383  struct addrinfo *q;
384  struct hostent *h;
385  struct sockaddr **psa = NULL;
386  int len;
387 
388  // TODO
389  // Currently, this never resolves IPv6 (need gethostbyname2, etc.)
390 # ifdef AF_INET6
391  if (hint->ai_family == AF_INET6)
392  {
393  if (p != NULL)
394  {
395  *result = p;
396  return 0;
397  }
398  return EAI_FAIL;
399  }
400 # endif
401 
402  h = gethostbyname(name);
403  if (h == NULL)
404  {
405  if (p != NULL)
406  {
407  // There already is a suitable result
408  *result = p;
409  return 0;
410  }
411 
412  switch (h_errno)
413  {
414  case HOST_NOT_FOUND:
415  return EAI_NONAME;
416  case TRY_AGAIN:
417  return EAI_AGAIN;
418  case NO_RECOVERY:
419  return EAI_FAIL;
420  case NO_ADDRESS:
421  return EAI_NODATA;
422  default:
423  // EH!?
424  return EAI_FAIL;
425  }
426  }
427 
428  q = (addrinfo*)malloc(sizeof(*q));
429  if (q == NULL)
430  {
431  freeaddrinfo(p);
432  return EAI_MEMORY;
433  }
434 
435  // convert the hostent to addrinfo
436  if (h->h_addrtype == AF_INET && (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC))
437  len = sizeof(struct sockaddr_in);
438 # ifdef AF_INET6
439  else if (h->h_addrtype == AF_INET6 && (hint->ai_family == AF_INET6 ||
440  hint->ai_family == AF_UNSPEC))
441  len = sizeof(struct sockaddr_in6);
442 # endif
443  else
444  {
445  // We don't know what to do with these addresses
446  // Or gethostbyname returned information we don't want
447  if (p != NULL)
448  {
449  *result = p;
450  return 0;
451  }
452  return EAI_NODATA;
453  }
454 
455  q->ai_flags = 0;
456  q->ai_family = h->h_addrtype;
457  q->ai_socktype = hint->ai_socktype;
458  q->ai_protocol = protonum;
459  q->ai_addrlen = len;
460 
461  q->ai_addr = (sockaddr*)malloc(len);
462  if (q->ai_addr == NULL)
463  {
464  free(q);
465  freeaddrinfo(p);
466  return EAI_MEMORY;
467  }
468  if (h->h_addrtype == AF_INET)
469  {
470  struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr;
471  sin->sin_family = AF_INET;
472 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
473  sin->sin_len = sizeof(*sin);
474 # endif
475  sin->sin_port = portnum;
476  memcpy(&sin->sin_addr, h->h_addr, h->h_length);
477  }
478 # ifdef AF_INET6
479  else if (h->h_addrtype == AF_INET6)
480  {
481  struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr;
482  sin6->sin6_family = AF_INET6;
483 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
484  sin6->sin6_len = sizeof(*sin6);
485 # endif
486  sin6->sin6_port = portnum;
487  sin6->sin6_flowinfo = 0;
488  memcpy(&sin6->sin6_addr, h->h_addr, h->h_length);
489  sin6->sin6_scope_id = 0;
490  }
491 # endif
492 
493  if (hint->ai_flags & AI_CANONNAME)
494  q->ai_canonname = qstrdup(h->h_name);
495  else
496  q->ai_canonname = NULL;
497 
498  q->ai_next = p;
499  p = q;
500 
501  // cycle through the rest of the hosts;
502  for (psa = (sockaddr**)h->h_addr_list + 1; *psa; psa++)
503  {
504  q = (addrinfo*)malloc(sizeof(*q));
505  if (q == NULL)
506  {
507  freeaddrinfo(p);
508  return EAI_MEMORY;
509  }
510  memcpy(q, p, sizeof(*q));
511 
512  q->ai_addr = (sockaddr*)malloc(h->h_length);
513  if (q->ai_addr == NULL)
514  {
515  freeaddrinfo(p);
516  free(q);
517  return EAI_MEMORY;
518  }
519  if (h->h_addrtype == AF_INET)
520  {
521  struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr;
522  sin->sin_family = AF_INET;
523 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
524  sin->sin_len = sizeof(*sin);
525 # endif
526  sin->sin_port = portnum;
527  memcpy(&sin->sin_addr, *psa, h->h_length);
528  }
529 # ifdef AF_INET6
530  else if (h->h_addrtype == AF_INET6)
531  {
532  struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr;
533  sin6->sin6_family = AF_INET6;
534 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
535  sin6->sin6_len = sizeof(*sin6);
536 # endif
537  sin6->sin6_port = portnum;
538  sin6->sin6_flowinfo = 0;
539  memcpy(&sin6->sin6_addr, *psa, h->h_length);
540  sin6->sin6_scope_id = 0;
541  }
542 # endif
543 
544  if (q->ai_canonname != NULL)
545  q->ai_canonname = qstrdup(q->ai_canonname);
546 
547  q->ai_next = p;
548  p = q;
549  }
550 
551  *result = p;
552  return 0; // Whew! Success!
553 }
554 
555 static int make_inet(const char *name, int portnum, int protonum, struct addrinfo *p,
556  const struct addrinfo *hint, struct addrinfo** result)
557 {
558  struct addrinfo *q;
559 
560  do
561  {
562  // This 'do' is here just so that we can 'break' out of it
563 
564  if (name != NULL)
565  {
566  // first, try to use inet_pton before resolving
567  // it will catch IP addresses given without having to go to lookup
568  struct sockaddr_in *sin;
569  struct in_addr in;
570 # ifdef AF_INET6
571  struct sockaddr_in6 *sin6;
572  struct in6_addr in6;
573 
574  if (hint->ai_family == AF_INET6 || (hint->ai_family == AF_UNSPEC &&
575  strchr(name, ':') != NULL))
576  {
577  // yes, this is IPv6
578  if (inet_pton(AF_INET6, name, &in6) != 1)
579  {
580  if (hint->ai_flags & AI_NUMERICHOST)
581  {
582  freeaddrinfo(p);
583  return EAI_FAIL;
584  }
585  break; // not a numeric host
586  }
587 
588  sin6 = (sockaddr_in6*)malloc(sizeof(*sin6));
589  if (sin6 == NULL)
590  {
591  freeaddrinfo(p);
592  return EAI_MEMORY;
593  }
594  memcpy(&sin6->sin6_addr, &in6, sizeof(in6));
595 
596  if (strchr(name, '%') != NULL)
597  {
598  errno = 0;
599  sin6->sin6_scope_id = strtoul(strchr(name, '%') + 1, NULL, 10);
600  if (errno != 0)
601  sin6->sin6_scope_id = 0; // no interface
602  }
603 
604  q = (addrinfo*)malloc(sizeof(*q));
605  if (q == NULL)
606  {
607  freeaddrinfo(p);
608  free(sin6);
609  return EAI_MEMORY;
610  }
611 
612  sin6->sin6_family = AF_INET6;
613 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
614  sin6->sin6_len = sizeof(*sin6);
615 # endif
616  sin6->sin6_port = portnum;
617  sin6->sin6_flowinfo = 0;
618 
619  q->ai_flags = 0;
620  q->ai_family = AF_INET6;
621  q->ai_socktype = hint->ai_socktype;
622  q->ai_protocol = protonum;
623  q->ai_addrlen = sizeof(*sin6);
624  q->ai_canonname = NULL;
625  q->ai_addr = (sockaddr*)sin6;
626  q->ai_next = p;
627 
628  *result = q;
629  return 0; // success!
630  }
631 # endif // AF_INET6
632 
633  if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)
634  {
635  // This has to be IPv4
636  if (inet_pton(AF_INET, name, &in) != 1)
637  {
638  if (hint->ai_flags & AI_NUMERICHOST)
639  {
640  freeaddrinfo(p);
641  return EAI_FAIL; // invalid, I guess
642  }
643  break; // not a numeric host, do lookup
644  }
645 
646  sin = (sockaddr_in*)malloc(sizeof(*sin));
647  if (sin == NULL)
648  {
649  freeaddrinfo(p);
650  return EAI_MEMORY;
651  }
652 
653  q = (addrinfo*)malloc(sizeof(*q));
654  if (q == NULL)
655  {
656  freeaddrinfo(p);
657  free(sin);
658  return EAI_MEMORY;
659  }
660 
661  sin->sin_family = AF_INET;
662 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
663  sin->sin_len = sizeof(*sin);
664 # endif
665  sin->sin_port = portnum;
666  sin->sin_addr = in;
667 
668  q->ai_flags = 0;
669  q->ai_family = AF_INET;
670  q->ai_socktype = hint->ai_socktype;
671  q->ai_protocol = protonum;
672  q->ai_addrlen = sizeof(*sin);
673  q->ai_canonname = NULL;
674  q->ai_addr = (sockaddr*)sin;
675  q->ai_next = p;
676  *result = q;
677  return 0;
678  }
679 
680  // Eh, what!?
681  // One of the two above has to have matched
682  kError() << "I wasn't supposed to get here!";
683  }
684  } while (false);
685 
686  // This means localhost
687  if (name == NULL)
688  {
689  struct sockaddr_in *sin = (sockaddr_in*)malloc(sizeof(*sin));
690 # ifdef AF_INET6
691  struct sockaddr_in6 *sin6;
692 # endif
693 
694  if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)
695  {
696  if (sin == NULL)
697  {
698  free(sin);
699  freeaddrinfo(p);
700  return EAI_MEMORY;
701  }
702 
703  // Do IPv4 first
704  q = (addrinfo*)malloc(sizeof(*q));
705  if (q == NULL)
706  {
707  free(sin);
708  freeaddrinfo(p);
709  return EAI_MEMORY;
710  }
711 
712  sin->sin_family = AF_INET;
713 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
714  sin->sin_len = sizeof(*sin);
715 # endif
716  sin->sin_port = portnum;
717  if (hint->ai_flags & AI_PASSIVE)
718  *(quint32*)&sin->sin_addr = INADDR_ANY;
719  else
720  *(quint32*)&sin->sin_addr = htonl(INADDR_LOOPBACK);
721  q->ai_flags = 0;
722  q->ai_family = AF_INET;
723  q->ai_socktype = hint->ai_socktype;
724  q->ai_protocol = protonum;
725  q->ai_addrlen = sizeof(*sin);
726  q->ai_canonname = NULL;
727  q->ai_addr = (sockaddr*)sin;
728  q->ai_next = p;
729  p = q;
730  }
731 
732 # ifdef AF_INET6
733  // Try now IPv6
734 
735  if (hint->ai_family == AF_INET6 || hint->ai_family == AF_UNSPEC)
736  {
737  sin6 = (sockaddr_in6*)malloc(sizeof(*sin6));
738  q = (addrinfo*)malloc(sizeof(*q));
739  if (q == NULL || sin6 == NULL)
740  {
741  free(sin6);
742  free(q);
743  freeaddrinfo(p);
744  return EAI_MEMORY;
745  }
746 
747  sin6->sin6_family = AF_INET6;
748 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
749  sin6->sin6_len = sizeof(*sin6);
750 # endif
751  sin6->sin6_port = portnum;
752  sin6->sin6_flowinfo = 0;
753  sin6->sin6_scope_id = 0;
754 
755  // We don't want to use in6addr_loopback and in6addr_any
756  memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
757  if ((hint->ai_flags & AI_PASSIVE) == 0)
758  ((char*)&sin6->sin6_addr)[15] = 1;
759 
760  q->ai_flags = 0;
761  q->ai_family = AF_INET6;
762  q->ai_socktype = hint->ai_socktype;
763  q->ai_protocol = protonum;
764  q->ai_addrlen = sizeof(*sin6);
765  q->ai_canonname = NULL;
766  q->ai_addr = (sockaddr*)sin6;
767  q->ai_next = p;
768  p = q;
769  }
770 
771 # endif // AF_INET6
772 
773  *result = p;
774  return 0; // success!
775  }
776 
777  return inet_lookup(name, portnum, protonum, p, hint, result);
778 }
779 
780 
781 int getaddrinfo(const char *name, const char *serv,
782  const struct addrinfo* hint,
783  struct addrinfo** result)
784 {
785  unsigned short portnum; // remember to store in network byte order
786  int protonum = IPPROTO_TCP;
787  const char *proto = "tcp";
788  struct addrinfo *p = NULL;
789 
790  // Sanity checks:
791  if (hint == NULL || result == NULL)
792  return EAI_BADFLAGS;
793  if (hint->ai_family != AF_UNSPEC && hint->ai_family != AF_UNIX &&
794  hint->ai_family != AF_INET
795 # ifdef AF_INET6
796  && hint->ai_family != AF_INET6
797 # endif
798  )
799  return EAI_FAMILY;
800  if (hint->ai_socktype != 0 && hint->ai_socktype != SOCK_STREAM &&
801  hint->ai_socktype != SOCK_DGRAM)
802  return EAI_SOCKTYPE;
803 
804  // Treat hostname of "*" as NULL, which means localhost
805  if (name != NULL && ((*name == '*' && name[1] == '\0') || *name == '\0'))
806  name = NULL;
807  // Treat service of "*" as NULL, which I guess means no port (0)
808  if (serv != NULL && ((*serv == '*' && serv[1] == '\0') || *serv == '\0'))
809  serv = NULL;
810 
811  if (name == NULL && serv == NULL) // what the hell do you want?
812  return EAI_NONAME;
813 
814  // This is just to make it easier
815  if (name != NULL && strcmp(name, "localhost") == 0)
816  name = NULL;
817 
818  // First, check for a Unix socket
819  // family must be either AF_UNIX or AF_UNSPEC
820  // either of name or serv must be set, the other must be NULL or empty
821  if (hint->ai_family == AF_UNIX || hint->ai_family == AF_UNSPEC)
822  {
823  if (name != NULL && serv != NULL)
824  {
825  // This is not allowed
826  if (hint->ai_family == AF_UNIX)
827  return EAI_BADFLAGS;
828  }
829  else
830  {
831  p = make_unix(name, serv);
832  if (p == NULL)
833  return EAI_MEMORY;
834 
835  p->ai_socktype = hint->ai_socktype;
836  // If the name/service started with a slash, then this *IS*
837  // only a Unix socket. Return.
838  if (hint->ai_family == AF_UNIX || ((name != NULL && *name == '/') ||
839  (serv != NULL && *serv == '/')))
840  {
841  *result = p;
842  return 0; // successful lookup
843  }
844  }
845  }
846 
847  // Lookup the service name, if required
848  if (serv != NULL)
849  {
850  char *tail;
851  struct servent *sent;
852 
853  portnum = htons((unsigned)strtoul(serv, &tail, 10));
854  if (*tail != '\0')
855  {
856  // not a number. We have to do the lookup
857  if (hint->ai_socktype == SOCK_DGRAM)
858  {
859  proto = "udp";
860  protonum = IPPROTO_UDP;
861  }
862 
863  sent = getservbyname(serv, proto);
864  if (sent == NULL) // no service?
865  {
866  if (p == NULL)
867  return EAI_NONAME;
868  else
869  return 0; // a Unix socket available
870  }
871 
872  portnum = sent->s_port;
873  }
874  }
875  else
876  portnum = 0; // no port number
877 
878  return make_inet(name, portnum, protonum, p, hint, result);
879 }
880 
881 void freeaddrinfo(struct addrinfo *p)
882 {
883  dofreeaddrinfo(p);
884 }
885 
886 #ifndef HAVE_GAI_STRERROR_PROTO
887 char *gai_strerror(int errorcode)
888 {
889  static const char messages[] =
890  {
891  I18N_NOOP("no error")"\0" // 0
892  I18N_NOOP("address family for nodename not supported")"\0" // EAI_ADDRFAMILY
893  I18N_NOOP("temporary failure in name resolution")"\0" // EAI_AGAIN
894  I18N_NOOP("invalid value for 'ai_flags'")"\0" // EAI_BADFLAGS
895  I18N_NOOP("non-recoverable failure in name resolution")"\0" // EAI_FAIL
896  I18N_NOOP("'ai_family' not supported")"\0" // EAI_FAMILY
897  I18N_NOOP("memory allocation failure")"\0" // EAI_MEMORY
898  I18N_NOOP("no address associated with nodename")"\0" // EAI_NODATA
899  I18N_NOOP("name or service not known")"\0" // EAI_NONAME
900  I18N_NOOP("servname not supported for ai_socktype")"\0" // EAI_SERVICE
901  I18N_NOOP("'ai_socktype' not supported")"\0" // EAI_SOCKTYPE
902  I18N_NOOP("system error")"\0" // EAI_SYSTEM
903  "\0"
904  };
905 
906  static const int messages_indices[] =
907  {
908  0, 9, 51, 88, 117, 160, 186, 212,
909  248, 274, 313, 341, 0
910  };
911 
912  Q_ASSERT(sizeof(messages_indices)/sizeof(messages_indices[0]) >= EAI_SYSTEM);
913  if (errorcode > EAI_SYSTEM || errorcode < 0)
914  return NULL;
915 
916  static char buffer[200];
917  strcpy(buffer, i18n(messages + messages_indices[errorcode]).toLocal8Bit());
918  return buffer;
919 }
920 #endif
921 
922 static void findport(unsigned short port, char *serv, size_t servlen, int flags)
923 {
924  if (serv == NULL)
925  return;
926 
927  if ((flags & NI_NUMERICSERV) == 0)
928  {
929  struct servent *sent;
930  sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp");
931  if (sent != NULL && servlen > strlen(sent->s_name))
932  {
933  strcpy(serv, sent->s_name);
934  return;
935  }
936  }
937 
938  qsnprintf(serv, servlen, "%u", ntohs(port));
939 }
940 
941 int getnameinfo(const struct sockaddr *sa, kde_socklen_t salen,
942  char *host, size_t hostlen, char *serv, size_t servlen,
943  int flags)
944 {
945  union
946  {
947  const sockaddr *sa;
948  const sockaddr_un *_sun;
949  const sockaddr_in *sin;
950  const sockaddr_in6 *sin6;
951  } s;
952 
953  if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0))
954  return 1;
955 
956  s.sa = sa;
957  if (s.sa->sa_family == AF_UNIX)
958  {
959  if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1)
960  return 1; // invalid socket
961 
962  if (servlen && serv != NULL)
963  *serv = '\0';
964  if (host != NULL && hostlen > strlen(s._sun->sun_path))
965  strcpy(host, s._sun->sun_path);
966 
967  return 0;
968  }
969  else if (s.sa->sa_family == AF_INET)
970  {
971  if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr))
972  return 1; // invalid socket
973 
974  if (flags & NI_NUMERICHOST)
975  inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
976  else
977  {
978  // have to do lookup
979  struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
980  AF_INET);
981  if (h == NULL && flags & NI_NAMEREQD)
982  return 1;
983  else if (h == NULL)
984  inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
985  else if (host != NULL && hostlen > strlen(h->h_name))
986  strcpy(host, h->h_name);
987  else
988  return 1; // error
989  }
990 
991  findport(s.sin->sin_port, serv, servlen, flags);
992  }
993 # ifdef AF_INET6
994  else if (s.sa->sa_family == AF_INET6)
995  {
996  if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr))
997  return 1; // invalid socket
998 
999  if (flags & NI_NUMERICHOST)
1000  inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
1001  else
1002  {
1003  // have to do lookup
1004  struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
1005  AF_INET6);
1006  if (h == NULL && flags & NI_NAMEREQD)
1007  return 1;
1008  else if (h == NULL)
1009  inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
1010  else if (host != NULL && hostlen > strlen(h->h_name))
1011  strcpy(host, h->h_name);
1012  else
1013  return 1; // error
1014  }
1015 
1016  findport(s.sin6->sin6_port, serv, servlen, flags);
1017  }
1018 # endif // AF_INET6
1019 
1020  return 1; // invalid family
1021 }
1022 
1023 #endif // HAVE_GETADDRINFO
1024 
1025 #ifndef HAVE_INET_NTOP
1026 
1027 #define KRF_inet_ntop KRF_USING_OWN_INET_NTOP
1028 
1029 static void add_dwords(char *buf, quint16 *dw, int count)
1030 {
1031  int i = 1;
1032  sprintf(buf + strlen(buf), "%x", ntohs(dw[0]));
1033  while (--count)
1034  sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++]));
1035 }
1036 
1037 const char* inet_ntop(int af, const void *cp, char *buf, size_t len)
1038 {
1039  char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1];
1040  quint8 *data = (quint8*)cp;
1041 
1042  if (af == AF_INET)
1043  {
1044  sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]);
1045 
1046  if (len > strlen(buf2))
1047  {
1048  strcpy(buf, buf2);
1049  return buf;
1050  }
1051 
1052  errno = ENOSPC;
1053  return NULL; // failed
1054  }
1055 
1056 # ifdef AF_INET6
1057  if (af == AF_INET6)
1058  {
1059  quint16 *p = (quint16*)data;
1060  quint16 *longest = NULL, *cur = NULL;
1061  int longest_length = 0, cur_length;
1062  int i;
1063 
1064  if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p))
1065  sprintf(buf2, "::%s%u.%u.%u.%u",
1066  KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "",
1067  buf[12], buf[13], buf[14], buf[15]);
1068  else
1069  {
1070  // find the longest sequence of zeroes
1071  for (i = 0; i < 8; --i)
1072  if (cur == NULL && p[i] == 0)
1073  {
1074  // a zero, start the sequence
1075  cur = p + i;
1076  cur_length = 1;
1077  }
1078  else if (cur != NULL && p[i] == 0)
1079  // part of the sequence
1080  cur_length++;
1081  else if (cur != NULL && p[i] != 0)
1082  {
1083  // end of the sequence
1084  if (cur_length > longest_length)
1085  {
1086  longest_length = cur_length;
1087  longest = cur;
1088  }
1089  cur = NULL; // restart sequence
1090  }
1091  if (cur != NULL && cur_length > longest_length)
1092  {
1093  longest_length = cur_length;
1094  longest = cur;
1095  }
1096 
1097  if (longest_length > 1)
1098  {
1099  // We have a candidate
1100  buf2[0] = '\0';
1101  if (longest != p)
1102  add_dwords(buf2, p, longest - p);
1103  strcat(buf2, "::");
1104  if (longest + longest_length < p + 8)
1105  add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length);
1106  }
1107  else
1108  {
1109  // Nope, no candidate
1110  buf2[0] = '\0';
1111  add_dwords(buf2, p, 8);
1112  }
1113  }
1114 
1115  if (strlen(buf2) < len)
1116  {
1117  strcpy(buf, buf2);
1118  return buf;
1119  }
1120 
1121  errno = ENOSPC;
1122  return NULL;
1123  }
1124 # endif
1125 
1126  errno = EAFNOSUPPORT;
1127  return NULL; // a family we don't know about
1128 }
1129 
1130 #else // HAVE_INET_NTOP
1131 
1132 #define KRF_inet_ntop 0
1133 
1134 #endif // HAVE_INET_NTOP
1135 
1136 #ifndef HAVE_INET_PTON
1137 
1138 #define KRF_inet_pton KRF_USING_OWN_INET_PTON
1139 int inet_pton(int af, const char *cp, void *buf)
1140 {
1141  if (af == AF_INET)
1142  {
1143  // Piece of cake
1144  unsigned p[4];
1145  unsigned char *q = (unsigned char*)buf;
1146  if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4)
1147  return 0;
1148 
1149  if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff)
1150  return 0;
1151 
1152  q[0] = p[0];
1153  q[1] = p[1];
1154  q[2] = p[2];
1155  q[3] = p[3];
1156 
1157  return 1;
1158  }
1159 
1160 # ifdef AF_INET6
1161  else if (af == AF_INET6)
1162  {
1163  quint16 addr[8];
1164  const char *p = cp;
1165  int n = 0, start = 8;
1166  bool has_v4 = strchr(p, '.') != NULL;
1167 
1168  memset(addr, 0, sizeof(addr));
1169 
1170  if (*p == '\0' || p[1] == '\0')
1171  return 0; // less than 2 chars is not valid
1172 
1173  if (*p == ':' && p[1] == ':')
1174  {
1175  start = 0;
1176  p += 2;
1177  }
1178  while (*p)
1179  {
1180  if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0)
1181  {
1182  // successful v4 convertion
1183  addr[n] = ntohs(addr[n]);
1184  n++;
1185  addr[n] = ntohs(addr[n]);
1186  n++;
1187  break;
1188  }
1189  if (sscanf(p, "%hx", addr + n++) != 1)
1190  return 0;
1191 
1192  while (*p && *p != ':')
1193  p++;
1194  if (!*p)
1195  break;
1196  p++;
1197 
1198  if (*p == ':') // another ':'?
1199  {
1200  if (start != 8)
1201  return 0; // two :: were found
1202  start = n;
1203  p++;
1204  }
1205  }
1206 
1207  // if start is not 8, then a "::" was found at word 'start'
1208  // n is the number of converted words
1209  // n == 8 means everything was converted and no moving is necessary
1210  // n < 8 means that we have to move n - start words 8 - n words to the right
1211  if (start == 8 && n != 8)
1212  return 0; // bad conversion
1213  memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(quint16));
1214  memset(addr + start, 0, (8 - n) * sizeof(quint16));
1215 
1216  // check the byte order
1217  // The compiler should optimize this out in big endian machines
1218  if (htons(0x1234) != 0x1234)
1219  for (n = 0; n < 8; ++n)
1220  addr[n] = htons(addr[n]);
1221 
1222  memcpy(buf, addr, sizeof(addr));
1223  return 1;
1224  }
1225 # endif
1226 
1227  errno = EAFNOSUPPORT;
1228  return -1; // unknown family
1229 }
1230 
1231 #else // HAVE_INET_PTON
1232 
1233 #define KRF_inet_pton 0
1234 
1235 #endif // HAVE_INET_PTON
1236 
1237 #ifdef AF_INET6
1238 # define KRF_afinet6 KRF_KNOWS_AF_INET6
1239 #else
1240 # define KRF_afinet6 0
1241 #endif
1242 
1243 namespace KDE
1244 {
1246  extern const int resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton;
1247 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue Jul 17 2012 07:26:03 by doxygen 1.8.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs-4.8.4 API Reference

Skip menu "kdelibs-4.8.4 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal