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

tdecore

  • tdecore
netsupp.cpp
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 <tqglobal.h>
32 
33 // This is so that, if addrinfo is defined, it doesn't clobber our definition
34 // It might be defined in the few cases in which we are replacing the system's
35 // broken getaddrinfo
36 #include <netdb.h>
37 
38 #include "config.h"
39 #include "kdebug.h"
40 #include "tdelocale.h"
41 
42 #ifndef IN6_IS_ADDR_V4MAPPED
43 #define NEED_IN6_TESTS
44 #endif
45 #undef CLOBBER_IN6
46 #include "netsupp.h"
47 
48 #if defined(__hpux) || defined(_HPUX_SOURCE)
49 extern int h_errno;
50 #endif
51 
52 #include <tdemacros.h>
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 = strdup(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 (getenv("TDE_NO_IPV6"))
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  q = (addrinfo*)malloc(sizeof(*q));
403  if (q == NULL)
404  {
405  freeaddrinfo(p);
406  return EAI_MEMORY;
407  }
408 
409  h = gethostbyname(name);
410  if (h == NULL)
411  {
412  if (p != NULL)
413  {
414  // There already is a suitable result
415  *result = p;
416  return 0;
417  }
418 
419  switch (h_errno)
420  {
421  case HOST_NOT_FOUND:
422  return EAI_NONAME;
423  case TRY_AGAIN:
424  return EAI_AGAIN;
425  case NO_RECOVERY:
426  return EAI_FAIL;
427  case NO_ADDRESS:
428  return EAI_NODATA;
429  default:
430  // EH!?
431  return EAI_FAIL;
432  }
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 = strdup(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 = strdup(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  kdError() << "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  *(TQ_UINT32*)&sin->sin_addr = INADDR_ANY;
719  else
720  *(TQ_UINT32*)&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 char *gai_strerror(int errorcode)
887 {
888  static const char * const messages[] =
889  {
890  I18N_NOOP("no error"), // 0
891  I18N_NOOP("address family for nodename not supported"), // EAI_ADDRFAMILY
892  I18N_NOOP("temporary failure in name resolution"), // EAI_AGAIN
893  I18N_NOOP("invalid value for 'ai_flags'"), // EAI_BADFLAGS
894  I18N_NOOP("non-recoverable failure in name resolution"), // EAI_FAIL
895  I18N_NOOP("'ai_family' not supported"), // EAI_FAMILY
896  I18N_NOOP("memory allocation failure"), // EAI_MEMORY
897  I18N_NOOP("no address associated with nodename"), // EAI_NODATA
898  I18N_NOOP("name or service not known"), // EAI_NONAME
899  I18N_NOOP("servname not supported for ai_socktype"), // EAI_SERVICE
900  I18N_NOOP("'ai_socktype' not supported"), // EAI_SOCKTYPE
901  I18N_NOOP("system error") // EAI_SYSTEM
902  };
903 
904  if (errorcode > EAI_SYSTEM || errorcode < 0)
905  return NULL;
906 
907  static char buffer[200];
908  strcpy(buffer, i18n(messages[errorcode]).local8Bit());
909  return buffer;
910 }
911 
912 static void findport(unsigned short port, char *serv, size_t servlen, int flags)
913 {
914  if (serv == NULL)
915  return;
916 
917  if ((flags & NI_NUMERICSERV) == 0)
918  {
919  struct servent *sent;
920  sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp");
921  if (sent != NULL && servlen > strlen(sent->s_name))
922  {
923  strcpy(serv, sent->s_name);
924  return;
925  }
926  }
927 
928  snprintf(serv, servlen, "%u", ntohs(port));
929 }
930 
931 int getnameinfo(const struct sockaddr *sa, ksocklen_t salen,
932  char *host, size_t hostlen, char *serv, size_t servlen,
933  int flags)
934 {
935  union
936  {
937  const sockaddr *sa;
938  const sockaddr_un *_sun;
939  const sockaddr_in *sin;
940  const sockaddr_in6 *sin6;
941  } s;
942 
943  if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0))
944  return 1;
945 
946  s.sa = sa;
947  if (s.sa->sa_family == AF_UNIX)
948  {
949  if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1)
950  return 1; // invalid socket
951 
952  if (servlen && serv != NULL)
953  *serv = '\0';
954  if (host != NULL && hostlen > strlen(s._sun->sun_path))
955  strcpy(host, s._sun->sun_path);
956 
957  return 0;
958  }
959  else if (s.sa->sa_family == AF_INET)
960  {
961  if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr))
962  return 1; // invalid socket
963 
964  if (flags & NI_NUMERICHOST)
965  inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
966  else
967  {
968  // have to do lookup
969  struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
970  AF_INET);
971  if (h == NULL && flags & NI_NAMEREQD)
972  return 1;
973  else if (h == NULL)
974  inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
975  else if (host != NULL && hostlen > strlen(h->h_name))
976  strcpy(host, h->h_name);
977  else
978  return 1; // error
979  }
980 
981  findport(s.sin->sin_port, serv, servlen, flags);
982  }
983 # ifdef AF_INET6
984  else if (s.sa->sa_family == AF_INET6)
985  {
986  if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr))
987  return 1; // invalid socket
988 
989  if (flags & NI_NUMERICHOST)
990  inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
991  else
992  {
993  // have to do lookup
994  struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
995  AF_INET6);
996  if (h == NULL && flags & NI_NAMEREQD)
997  return 1;
998  else if (h == NULL)
999  inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
1000  else if (host != NULL && hostlen > strlen(h->h_name))
1001  strcpy(host, h->h_name);
1002  else
1003  return 1; // error
1004  }
1005 
1006  findport(s.sin6->sin6_port, serv, servlen, flags);
1007  }
1008 # endif // AF_INET6
1009 
1010  return 1; // invalid family
1011 }
1012 
1013 #endif // HAVE_GETADDRINFO
1014 
1015 #ifndef HAVE_INET_NTOP
1016 
1017 #define KRF_inet_ntop KRF_USING_OWN_INET_NTOP
1018 
1019 static void add_dwords(char *buf, TQ_UINT16 *dw, int count)
1020 {
1021  int i = 1;
1022  sprintf(buf + strlen(buf), "%x", ntohs(dw[0]));
1023  while (--count)
1024  sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++]));
1025 }
1026 
1027 const char* inet_ntop(int af, const void *cp, char *buf, size_t len)
1028 {
1029  char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1];
1030  TQ_UINT8 *data = (TQ_UINT8*)cp;
1031 
1032  if (af == AF_INET)
1033  {
1034  sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]);
1035 
1036  if (len > strlen(buf2))
1037  {
1038  strcpy(buf, buf2);
1039  return buf;
1040  }
1041 
1042  errno = ENOSPC;
1043  return NULL; // failed
1044  }
1045 
1046 # ifdef AF_INET6
1047  if (af == AF_INET6)
1048  {
1049  TQ_UINT16 *p = (TQ_UINT16*)data;
1050  TQ_UINT16 *longest = NULL, *cur = NULL;
1051  int longest_length = 0, cur_length;
1052  int i;
1053 
1054  if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p))
1055  sprintf(buf2, "::%s%u.%u.%u.%u",
1056  KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "",
1057  buf[12], buf[13], buf[14], buf[15]);
1058  else
1059  {
1060  // find the longest sequence of zeroes
1061  for (i = 0; i < 8; i++)
1062  if (cur == NULL && p[i] == 0)
1063  {
1064  // a zero, start the sequence
1065  cur = p + i;
1066  cur_length = 1;
1067  }
1068  else if (cur != NULL && p[i] == 0)
1069  // part of the sequence
1070  cur_length++;
1071  else if (cur != NULL && p[i] != 0)
1072  {
1073  // end of the sequence
1074  if (cur_length > longest_length)
1075  {
1076  longest_length = cur_length;
1077  longest = cur;
1078  }
1079  cur = NULL; // restart sequence
1080  }
1081  if (cur != NULL && cur_length > longest_length)
1082  {
1083  longest_length = cur_length;
1084  longest = cur;
1085  }
1086 
1087  if (longest_length > 1)
1088  {
1089  // We have a candidate
1090  buf2[0] = '\0';
1091  if (longest != p)
1092  add_dwords(buf2, p, longest - p);
1093  strcat(buf2, "::");
1094  if (longest + longest_length < p + 8)
1095  add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length);
1096  }
1097  else
1098  {
1099  // Nope, no candidate
1100  buf2[0] = '\0';
1101  add_dwords(buf2, p, 8);
1102  }
1103  }
1104 
1105  if (strlen(buf2) < len)
1106  {
1107  strcpy(buf, buf2);
1108  return buf;
1109  }
1110 
1111  errno = ENOSPC;
1112  return NULL;
1113  }
1114 # endif
1115 
1116  errno = EAFNOSUPPORT;
1117  return NULL; // a family we don't know about
1118 }
1119 
1120 #else // HAVE_INET_NTOP
1121 
1122 #define KRF_inet_ntop 0
1123 
1124 #endif // HAVE_INET_NTOP
1125 
1126 #ifndef HAVE_INET_PTON
1127 
1128 #define KRF_inet_pton KRF_USING_OWN_INET_PTON
1129 int inet_pton(int af, const char *cp, void *buf)
1130 {
1131  if (af == AF_INET)
1132  {
1133  // Piece of cake
1134  unsigned p[4];
1135  unsigned char *q = (unsigned char*)buf;
1136  if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4)
1137  return 0;
1138 
1139  if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff)
1140  return 0;
1141 
1142  q[0] = p[0];
1143  q[1] = p[1];
1144  q[2] = p[2];
1145  q[3] = p[3];
1146 
1147  return 1;
1148  }
1149 
1150 # ifdef AF_INET6
1151  else if (af == AF_INET6)
1152  {
1153  TQ_UINT16 addr[8];
1154  const char *p = cp;
1155  int n = 0, start = 8;
1156  bool has_v4 = strchr(p, '.') != NULL;
1157 
1158  memset(addr, 0, sizeof(addr));
1159 
1160  if (*p == '\0' || p[1] == '\0')
1161  return 0; // less than 2 chars is not valid
1162 
1163  if (*p == ':' && p[1] == ':')
1164  {
1165  start = 0;
1166  p += 2;
1167  }
1168  while (*p)
1169  {
1170  if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0)
1171  {
1172  // successful v4 convertion
1173  addr[n] = ntohs(addr[n]);
1174  n++;
1175  addr[n] = ntohs(addr[n]);
1176  n++;
1177  break;
1178  }
1179  if (sscanf(p, "%hx", addr + n++) != 1)
1180  return 0;
1181 
1182  while (*p && *p != ':')
1183  p++;
1184  if (!*p)
1185  break;
1186  p++;
1187 
1188  if (*p == ':') // another ':'?
1189  {
1190  if (start != 8)
1191  return 0; // two :: were found
1192  start = n;
1193  p++;
1194  }
1195  }
1196 
1197  // if start is not 8, then a "::" was found at word 'start'
1198  // n is the number of converted words
1199  // n == 8 means everything was converted and no moving is necessary
1200  // n < 8 means that we have to move n - start words 8 - n words to the right
1201  if (start == 8 && n != 8)
1202  return 0; // bad conversion
1203  memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(TQ_UINT16));
1204  memset(addr + start, 0, (8 - n) * sizeof(TQ_UINT16));
1205 
1206  // check the byte order
1207  // The compiler should optimise this out in big endian machines
1208  if (htons(0x1234) != 0x1234)
1209  for (n = 0; n < 8; n++)
1210  addr[n] = htons(addr[n]);
1211 
1212  memcpy(buf, addr, sizeof(addr));
1213  return 1;
1214  }
1215 # endif
1216 
1217  errno = EAFNOSUPPORT;
1218  return -1; // unknown family
1219 }
1220 
1221 #else // HAVE_INET_PTON
1222 
1223 #define KRF_inet_pton 0
1224 
1225 #endif // HAVE_INET_PTON
1226 
1227 #ifdef AF_INET6
1228 # define KRF_afinet6 KRF_KNOWS_AF_INET6
1229 #else
1230 # define KRF_afinet6 0
1231 #endif
1232 
1233 namespace KDE
1234 {
1236  extern const int TDE_EXPORT resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton;
1237 }
TDELocale::i18n
TQString i18n(const char *text)
i18n is the function that does everything you need to translate a string.
Definition: tdelocale.cpp:1976
TDELocale::I18N_NOOP
#define I18N_NOOP(x)
I18N_NOOP marks a string to be translated without translating it.
Definition: tdelocale.h:51
TDEGlobal::kdError
kdbgstream kdError(int area=0)
Returns an error stream.
Definition: kdebug.cpp:374
KDE
Namespace for general KDE functions.
Definition: ktypelist.h:350
KStdAction::name
const char * name(StdAction id)
tdelocale.h

tdecore

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

tdecore

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