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

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.8.13
This website is maintained by Timothy Pearson.