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