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

KDECore

  • kdecore
  • network
netsupp.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 2000,2001 Thiago Macieira <thiago.macieira@kdemail.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 **/
20
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <netinet/in.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <errno.h>
28#include <unistd.h>
29#include <arpa/inet.h>
30
31#include <QtCore/QBool>
32
33#include <kdebug.h>
34
35// This is so that, if addrinfo is defined, it doesn't clobber our definition
36// It might be defined in the few cases in which we are replacing the system's
37// broken getaddrinfo
38#include <netdb.h>
39
40#include <config.h>
41#include <config-network.h>
42#include "klocale.h"
43
44#ifndef IN6_IS_ADDR_V4MAPPED
45#define NEED_IN6_TESTS
46#endif
47#undef CLOBBER_IN6
48#include "netsupp.h" //krazy:exclude=includes (netsupp.h not installed; KDE3 compat code)
49
50#if defined(__hpux) || defined(_HPUX_SOURCE)
51extern int h_errno;
52#endif
53
54#if !defined(kde_sockaddr_in6)
55/*
56 * kde_sockaddr_in6 might have got defined even though we #undef'ed
57 * CLOBBER_IN6. This happens when we are compiling under --enable-final.
58 * However, in that case, if it was defined, that's because ksockaddr.cpp
59 * had it defined because sockaddr_in6 didn't exist, and so sockaddr_in6
60 * exists and is our kde_sockaddr_in6
61 */
62# define sockaddr_in6 kde_sockaddr_in6
63# define in6_addr kde_in6_addr
64#endif
65
66#ifdef offsetof
67#undef offsetof
68#endif
69#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
70
71/*
72 * These constants tell the flags in KDE::resolverFlags
73 * The user could (but shouldn't) test the variable to know what kind of
74 * resolution is supported
75 */
76#define KRF_KNOWS_AF_INET6 0x01 /* if present, the code knows about AF_INET6 */
77#define KRF_USING_OWN_GETADDRINFO 0x02 /* if present, we are using our own getaddrinfo */
78#define KRF_USING_OWN_INET_NTOP 0x04 /* if present, we are using our own inet_ntop */
79#define KRF_USING_OWN_INET_PTON 0x08 /* if present, we are using our own inet_pton */
80#define KRF_CAN_RESOLVE_UNIX 0x100 /* if present, the resolver can resolve Unix sockets */
81#define KRF_CAN_RESOLVE_IPV4 0x200 /* if present, the resolver can resolve to IPv4 */
82#define KRF_CAN_RESOLVE_IPV6 0x400 /* if present, the resolver can resolve to IPv6 */
83
84
85static 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
101void 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
129static struct addrinfo*
130make_unix(const char *name, const char *serv)
131{
132 const char *buf;
133 struct addrinfo *p;
134 struct sockaddr_un *_sun;
135 int len;
136
137 p = (addrinfo*)malloc(sizeof(*p));
138 if (p == NULL)
139 return NULL;
140 memset(p, 0, sizeof(*p));
141
142 if (name != NULL)
143 buf = name;
144 else
145 buf = serv;
146
147 // Calculate length of the binary representation
148 len = strlen(buf) + offsetof(struct sockaddr_un, sun_path) + 1;
149 if (*buf != '/')
150 len += 5; // strlen("/tmp/");
151
152 _sun = (sockaddr_un*)malloc(len);
153 if (_sun == NULL)
154 {
155 // Oops
156 free(p);
157 return NULL;
158 }
159
160 _sun->sun_family = AF_UNIX;
161# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
162 _sun->sun_len = len;
163# endif
164 if (*buf == '/')
165 *_sun->sun_path = '\0'; // empty it
166 else
167 strcpy(_sun->sun_path, "/tmp/");
168 strcat(_sun->sun_path, buf);
169
170 // Set the addrinfo
171 p->ai_family = AF_UNIX;
172 p->ai_addrlen = len;
173 p->ai_addr = (sockaddr*)_sun;
174 p->ai_canonname = qstrdup(buf);
175
176 return p;
177}
178
179// Ugh. I hate #ifdefs
180// Anyways, here's what this does:
181// KDE_IPV6_LOOKUP_MODE != 1, this function doesn't exist
182// AF_INET6 not defined, we say there is no IPv6 stack
183// otherwise, we try to create a socket.
184// returns: 1 for IPv6 stack available, 2 for not available
185#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1
186static int check_ipv6_stack()
187{
188# ifndef AF_INET6
189 return 2; // how can we check?
190# else
191 if (!qgetenv("KDE_NO_IPV6").isEmpty())
192 return 2;
193 int fd = ::socket(AF_INET6, SOCK_STREAM, 0);
194 if (fd == -1)
195 return 2;
196
197 ::close(fd);
198 return 1;
199# endif
200}
201#endif
202
203
204/*
205 * Reason for using this function: kde_getaddrinfo
206 *
207 * I decided to add this wrapper function for getaddrinfo
208 * and have this be called by KExtendedSocket instead of
209 * the real getaddrinfo so that we can make sure that the
210 * behavior is the desired one.
211 *
212 * Currently, the only "undesired" behavior is getaddrinfo
213 * not returning PF_UNIX sockets in some implementations.
214 *
215 * getaddrinfo and family are defined in POSIX 1003.1g
216 * (Protocol Independent Interfaces) and in RFC 2553
217 * (Basic Socket Interface for IPv6). Whereas the RFC is ambiguosly
218 * vague whether this family of functions should return Internet
219 * sockets only or not, the name of the POSIX draft says
220 * otherwise: it should be independent of protocol.
221 *
222 * So, my interpretation is that they should return every
223 * kind of socket available and known and that's how I
224 * designed KExtendedSocket on top of it.
225 *
226 * That's why there's this wrapper, to make sure PF_UNIX
227 * sockets are returned when expected.
228 */
229
230int 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
379static int inet_lookup(const char *name, int portnum, int protonum,
380 struct addrinfo *p, const struct addrinfo *hint,
381 struct addrinfo** result)
382{
383 struct addrinfo *q;
384 struct hostent *h;
385 struct sockaddr **psa = NULL;
386 int len;
387
388 // TODO
389 // Currently, this never resolves IPv6 (need gethostbyname2, etc.)
390# ifdef AF_INET6
391 if (hint->ai_family == AF_INET6)
392 {
393 if (p != NULL)
394 {
395 *result = p;
396 return 0;
397 }
398 return EAI_FAIL;
399 }
400# endif
401
402 h = gethostbyname(name);
403 if (h == NULL)
404 {
405 if (p != NULL)
406 {
407 // There already is a suitable result
408 *result = p;
409 return 0;
410 }
411
412 switch (h_errno)
413 {
414 case HOST_NOT_FOUND:
415 return EAI_NONAME;
416 case TRY_AGAIN:
417 return EAI_AGAIN;
418 case NO_RECOVERY:
419 return EAI_FAIL;
420 case NO_ADDRESS:
421 return EAI_NODATA;
422 default:
423 // EH!?
424 return EAI_FAIL;
425 }
426 }
427
428 q = (addrinfo*)malloc(sizeof(*q));
429 if (q == NULL)
430 {
431 freeaddrinfo(p);
432 return EAI_MEMORY;
433 }
434
435 // convert the hostent to addrinfo
436 if (h->h_addrtype == AF_INET && (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC))
437 len = sizeof(struct sockaddr_in);
438# ifdef AF_INET6
439 else if (h->h_addrtype == AF_INET6 && (hint->ai_family == AF_INET6 ||
440 hint->ai_family == AF_UNSPEC))
441 len = sizeof(struct sockaddr_in6);
442# endif
443 else
444 {
445 free(q);
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 = qstrdup(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 = qstrdup(q->ai_canonname);
547
548 q->ai_next = p;
549 p = q;
550 }
551
552 *result = p;
553 return 0; // Whew! Success!
554}
555
556static 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 kError() << "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 *(quint32*)&sin->sin_addr = INADDR_ANY;
720 else
721 *(quint32*)&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(sin);
743 free(sin6);
744 free(q);
745 freeaddrinfo(p);
746 return EAI_MEMORY;
747 }
748
749 sin6->sin6_family = AF_INET6;
750# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
751 sin6->sin6_len = sizeof(*sin6);
752# endif
753 sin6->sin6_port = portnum;
754 sin6->sin6_flowinfo = 0;
755 sin6->sin6_scope_id = 0;
756
757 // We don't want to use in6addr_loopback and in6addr_any
758 memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
759 if ((hint->ai_flags & AI_PASSIVE) == 0)
760 ((char*)&sin6->sin6_addr)[15] = 1;
761
762 q->ai_flags = 0;
763 q->ai_family = AF_INET6;
764 q->ai_socktype = hint->ai_socktype;
765 q->ai_protocol = protonum;
766 q->ai_addrlen = sizeof(*sin6);
767 q->ai_canonname = NULL;
768 q->ai_addr = (sockaddr*)sin6;
769 q->ai_next = p;
770 p = q;
771 }
772
773# endif // AF_INET6
774
775 *result = p;
776 free(sin);
777 return 0; // success!
778 }
779
780 return inet_lookup(name, portnum, protonum, p, hint, result);
781}
782
783
784int getaddrinfo(const char *name, const char *serv,
785 const struct addrinfo* hint,
786 struct addrinfo** result)
787{
788 unsigned short portnum; // remember to store in network byte order
789 int protonum = IPPROTO_TCP;
790 const char *proto = "tcp";
791 struct addrinfo *p = NULL;
792
793 // Sanity checks:
794 if (hint == NULL || result == NULL)
795 return EAI_BADFLAGS;
796 if (hint->ai_family != AF_UNSPEC && hint->ai_family != AF_UNIX &&
797 hint->ai_family != AF_INET
798# ifdef AF_INET6
799 && hint->ai_family != AF_INET6
800# endif
801 )
802 return EAI_FAMILY;
803 if (hint->ai_socktype != 0 && hint->ai_socktype != SOCK_STREAM &&
804 hint->ai_socktype != SOCK_DGRAM)
805 return EAI_SOCKTYPE;
806
807 // Treat hostname of "*" as NULL, which means localhost
808 if (name != NULL && ((*name == '*' && name[1] == '\0') || *name == '\0'))
809 name = NULL;
810 // Treat service of "*" as NULL, which I guess means no port (0)
811 if (serv != NULL && ((*serv == '*' && serv[1] == '\0') || *serv == '\0'))
812 serv = NULL;
813
814 if (name == NULL && serv == NULL) // what the hell do you want?
815 return EAI_NONAME;
816
817 // This is just to make it easier
818 if (name != NULL && strcmp(name, "localhost") == 0)
819 name = NULL;
820
821 // First, check for a Unix socket
822 // family must be either AF_UNIX or AF_UNSPEC
823 // either of name or serv must be set, the other must be NULL or empty
824 if (hint->ai_family == AF_UNIX || hint->ai_family == AF_UNSPEC)
825 {
826 if (name != NULL && serv != NULL)
827 {
828 // This is not allowed
829 if (hint->ai_family == AF_UNIX)
830 return EAI_BADFLAGS;
831 }
832 else
833 {
834 p = make_unix(name, serv);
835 if (p == NULL)
836 return EAI_MEMORY;
837
838 p->ai_socktype = hint->ai_socktype;
839 // If the name/service started with a slash, then this *IS*
840 // only a Unix socket. Return.
841 if (hint->ai_family == AF_UNIX || ((name != NULL && *name == '/') ||
842 (serv != NULL && *serv == '/')))
843 {
844 *result = p;
845 return 0; // successful lookup
846 }
847 }
848 }
849
850 // Lookup the service name, if required
851 if (serv != NULL)
852 {
853 char *tail;
854 struct servent *sent;
855
856 portnum = htons((unsigned)strtoul(serv, &tail, 10));
857 if (*tail != '\0')
858 {
859 // not a number. We have to do the lookup
860 if (hint->ai_socktype == SOCK_DGRAM)
861 {
862 proto = "udp";
863 protonum = IPPROTO_UDP;
864 }
865
866 sent = getservbyname(serv, proto);
867 if (sent == NULL) // no service?
868 {
869 if (p == NULL)
870 return EAI_NONAME;
871 else
872 return 0; // a Unix socket available
873 }
874
875 portnum = sent->s_port;
876 }
877 }
878 else
879 portnum = 0; // no port number
880
881 return make_inet(name, portnum, protonum, p, hint, result);
882}
883
884void freeaddrinfo(struct addrinfo *p)
885{
886 dofreeaddrinfo(p);
887}
888
889#ifndef HAVE_GAI_STRERROR_PROTO
890char *gai_strerror(int errorcode)
891{
892 static const char messages[] =
893 {
894 I18N_NOOP("no error")"\0" // 0
895 I18N_NOOP("address family for nodename not supported")"\0" // EAI_ADDRFAMILY
896 I18N_NOOP("temporary failure in name resolution")"\0" // EAI_AGAIN
897 I18N_NOOP("invalid value for 'ai_flags'")"\0" // EAI_BADFLAGS
898 I18N_NOOP("non-recoverable failure in name resolution")"\0" // EAI_FAIL
899 I18N_NOOP("'ai_family' not supported")"\0" // EAI_FAMILY
900 I18N_NOOP("memory allocation failure")"\0" // EAI_MEMORY
901 I18N_NOOP("no address associated with nodename")"\0" // EAI_NODATA
902 I18N_NOOP("name or service not known")"\0" // EAI_NONAME
903 I18N_NOOP("servname not supported for ai_socktype")"\0" // EAI_SERVICE
904 I18N_NOOP("'ai_socktype' not supported")"\0" // EAI_SOCKTYPE
905 I18N_NOOP("system error")"\0" // EAI_SYSTEM
906 "\0"
907 };
908
909 static const int messages_indices[] =
910 {
911 0, 9, 51, 88, 117, 160, 186, 212,
912 248, 274, 313, 341, 0
913 };
914
915 Q_ASSERT(sizeof(messages_indices)/sizeof(messages_indices[0]) >= EAI_SYSTEM);
916 if (errorcode > EAI_SYSTEM || errorcode < 0)
917 return NULL;
918
919 static char buffer[200];
920 strcpy(buffer, i18n(messages + messages_indices[errorcode]).toLocal8Bit());
921 return buffer;
922}
923#endif
924
925static void findport(unsigned short port, char *serv, size_t servlen, int flags)
926{
927 if (serv == NULL)
928 return;
929
930 if ((flags & NI_NUMERICSERV) == 0)
931 {
932 struct servent *sent;
933 sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp");
934 if (sent != NULL && servlen > strlen(sent->s_name))
935 {
936 strcpy(serv, sent->s_name);
937 return;
938 }
939 }
940
941 qsnprintf(serv, servlen, "%u", ntohs(port));
942}
943
944int getnameinfo(const struct sockaddr *sa, kde_socklen_t salen,
945 char *host, size_t hostlen, char *serv, size_t servlen,
946 int flags)
947{
948 union
949 {
950 const sockaddr *sa;
951 const sockaddr_un *_sun;
952 const sockaddr_in *sin;
953 const sockaddr_in6 *sin6;
954 } s;
955
956 if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0))
957 return 1;
958
959 s.sa = sa;
960 if (s.sa->sa_family == AF_UNIX)
961 {
962 if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1)
963 return 1; // invalid socket
964
965 if (servlen && serv != NULL)
966 *serv = '\0';
967 if (host != NULL && hostlen > strlen(s._sun->sun_path))
968 strcpy(host, s._sun->sun_path);
969
970 return 0;
971 }
972 else if (s.sa->sa_family == AF_INET)
973 {
974 if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr))
975 return 1; // invalid socket
976
977 if (flags & NI_NUMERICHOST)
978 inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
979 else
980 {
981 // have to do lookup
982 struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
983 AF_INET);
984 if (h == NULL && flags & NI_NAMEREQD)
985 return 1;
986 else if (h == NULL)
987 inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
988 else if (host != NULL && hostlen > strlen(h->h_name))
989 strcpy(host, h->h_name);
990 else
991 return 1; // error
992 }
993
994 findport(s.sin->sin_port, serv, servlen, flags);
995 }
996# ifdef AF_INET6
997 else if (s.sa->sa_family == AF_INET6)
998 {
999 if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr))
1000 return 1; // invalid socket
1001
1002 if (flags & NI_NUMERICHOST)
1003 inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
1004 else
1005 {
1006 // have to do lookup
1007 struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
1008 AF_INET6);
1009 if (h == NULL && flags & NI_NAMEREQD)
1010 return 1;
1011 else if (h == NULL)
1012 inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
1013 else if (host != NULL && hostlen > strlen(h->h_name))
1014 strcpy(host, h->h_name);
1015 else
1016 return 1; // error
1017 }
1018
1019 findport(s.sin6->sin6_port, serv, servlen, flags);
1020 }
1021# endif // AF_INET6
1022
1023 return 1; // invalid family
1024}
1025
1026#endif // HAVE_GETADDRINFO
1027
1028#ifndef HAVE_INET_NTOP
1029
1030#define KRF_inet_ntop KRF_USING_OWN_INET_NTOP
1031
1032static void add_dwords(char *buf, quint16 *dw, int count)
1033{
1034 int i = 1;
1035 sprintf(buf + strlen(buf), "%x", ntohs(dw[0]));
1036 while (--count)
1037 sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++]));
1038}
1039
1040const char* inet_ntop(int af, const void *cp, char *buf, size_t len)
1041{
1042 char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1];
1043 quint8 *data = (quint8*)cp;
1044
1045 if (af == AF_INET)
1046 {
1047 sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]);
1048
1049 if (len > strlen(buf2))
1050 {
1051 strcpy(buf, buf2);
1052 return buf;
1053 }
1054
1055 errno = ENOSPC;
1056 return NULL; // failed
1057 }
1058
1059# ifdef AF_INET6
1060 if (af == AF_INET6)
1061 {
1062 quint16 *p = (quint16*)data;
1063 quint16 *longest = NULL, *cur = NULL;
1064 int longest_length = 0, cur_length;
1065 int i;
1066
1067 if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p))
1068 sprintf(buf2, "::%s%u.%u.%u.%u",
1069 KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "",
1070 buf[12], buf[13], buf[14], buf[15]);
1071 else
1072 {
1073 // find the longest sequence of zeroes
1074 for (i = 0; i < 8; --i)
1075 if (cur == NULL && p[i] == 0)
1076 {
1077 // a zero, start the sequence
1078 cur = p + i;
1079 cur_length = 1;
1080 }
1081 else if (cur != NULL && p[i] == 0)
1082 // part of the sequence
1083 cur_length++;
1084 else if (cur != NULL && p[i] != 0)
1085 {
1086 // end of the sequence
1087 if (cur_length > longest_length)
1088 {
1089 longest_length = cur_length;
1090 longest = cur;
1091 }
1092 cur = NULL; // restart sequence
1093 }
1094 if (cur != NULL && cur_length > longest_length)
1095 {
1096 longest_length = cur_length;
1097 longest = cur;
1098 }
1099
1100 if (longest_length > 1)
1101 {
1102 // We have a candidate
1103 buf2[0] = '\0';
1104 if (longest != p)
1105 add_dwords(buf2, p, longest - p);
1106 strcat(buf2, "::");
1107 if (longest + longest_length < p + 8)
1108 add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length);
1109 }
1110 else
1111 {
1112 // Nope, no candidate
1113 buf2[0] = '\0';
1114 add_dwords(buf2, p, 8);
1115 }
1116 }
1117
1118 if (strlen(buf2) < len)
1119 {
1120 strcpy(buf, buf2);
1121 return buf;
1122 }
1123
1124 errno = ENOSPC;
1125 return NULL;
1126 }
1127# endif
1128
1129 errno = EAFNOSUPPORT;
1130 return NULL; // a family we don't know about
1131}
1132
1133#else // HAVE_INET_NTOP
1134
1135#define KRF_inet_ntop 0
1136
1137#endif // HAVE_INET_NTOP
1138
1139#ifndef HAVE_INET_PTON
1140
1141#define KRF_inet_pton KRF_USING_OWN_INET_PTON
1142int inet_pton(int af, const char *cp, void *buf)
1143{
1144 if (af == AF_INET)
1145 {
1146 // Piece of cake
1147 unsigned p[4];
1148 unsigned char *q = (unsigned char*)buf;
1149 if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4)
1150 return 0;
1151
1152 if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff)
1153 return 0;
1154
1155 q[0] = p[0];
1156 q[1] = p[1];
1157 q[2] = p[2];
1158 q[3] = p[3];
1159
1160 return 1;
1161 }
1162
1163# ifdef AF_INET6
1164 else if (af == AF_INET6)
1165 {
1166 quint16 addr[8];
1167 const char *p = cp;
1168 int n = 0, start = 8;
1169 bool has_v4 = strchr(p, '.') != NULL;
1170
1171 memset(addr, 0, sizeof(addr));
1172
1173 if (*p == '\0' || p[1] == '\0')
1174 return 0; // less than 2 chars is not valid
1175
1176 if (*p == ':' && p[1] == ':')
1177 {
1178 start = 0;
1179 p += 2;
1180 }
1181 while (*p)
1182 {
1183 if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0)
1184 {
1185 // successful v4 convertion
1186 addr[n] = ntohs(addr[n]);
1187 n++;
1188 addr[n] = ntohs(addr[n]);
1189 n++;
1190 break;
1191 }
1192 if (sscanf(p, "%hx", addr + n++) != 1)
1193 return 0;
1194
1195 while (*p && *p != ':')
1196 p++;
1197 if (!*p)
1198 break;
1199 p++;
1200
1201 if (*p == ':') // another ':'?
1202 {
1203 if (start != 8)
1204 return 0; // two :: were found
1205 start = n;
1206 p++;
1207 }
1208 }
1209
1210 // if start is not 8, then a "::" was found at word 'start'
1211 // n is the number of converted words
1212 // n == 8 means everything was converted and no moving is necessary
1213 // n < 8 means that we have to move n - start words 8 - n words to the right
1214 if (start == 8 && n != 8)
1215 return 0; // bad conversion
1216 memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(quint16));
1217 memset(addr + start, 0, (8 - n) * sizeof(quint16));
1218
1219 // check the byte order
1220 // The compiler should optimize this out in big endian machines
1221 if (htons(0x1234) != 0x1234)
1222 for (n = 0; n < 8; ++n)
1223 addr[n] = htons(addr[n]);
1224
1225 memcpy(buf, addr, sizeof(addr));
1226 return 1;
1227 }
1228# endif
1229
1230 errno = EAFNOSUPPORT;
1231 return -1; // unknown family
1232}
1233
1234#else // HAVE_INET_PTON
1235
1236#define KRF_inet_pton 0
1237
1238#endif // HAVE_INET_PTON
1239
1240#ifdef AF_INET6
1241# define KRF_afinet6 KRF_KNOWS_AF_INET6
1242#else
1243# define KRF_afinet6 0
1244#endif
1245
1246namespace KDE
1247{
1249 extern const int resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton;
1250}
quint32
kError
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
Definition: kdebug.h:187
kdebug.h
klocale.h
i18n
QString i18n(const char *text)
Returns a localized version of a string.
Definition: klocalizedstring.h:630
I18N_NOOP
#define I18N_NOOP(x)
I18N_NOOP marks a string to be translated without translating it.
Definition: klocalizedstring.h:51
KDE
Definition: netsupp.cpp:1247
KDE::resolverFlags
const int resolverFlags
offsetof
#define offsetof(TYPE, MEMBER)
Definition: netsupp.cpp:69
KRF_resolver
#define KRF_resolver
Definition: netsupp.cpp:369
inet_lookup
static int inet_lookup(const char *name, int portnum, int protonum, struct addrinfo *p, const struct addrinfo *hint, struct addrinfo **result)
TODO Try and use gethostbyname2_r before gethostbyname2 and gethostbyname.
Definition: netsupp.cpp:379
in6_addr
#define in6_addr
Definition: netsupp.cpp:63
KRF_afinet6
#define KRF_afinet6
Definition: netsupp.cpp:1243
dofreeaddrinfo
static void dofreeaddrinfo(struct addrinfo *ai)
Definition: netsupp.cpp:85
gai_strerror
char * gai_strerror(int errorcode)
Definition: netsupp.cpp:890
KRF_getaddrinfo
#define KRF_getaddrinfo
Definition: netsupp.cpp:368
make_unix
static struct addrinfo * make_unix(const char *name, const char *serv)
Definition: netsupp.cpp:130
KRF_inet_pton
#define KRF_inet_pton
Definition: netsupp.cpp:1141
add_dwords
static void add_dwords(char *buf, quint16 *dw, int count)
Definition: netsupp.cpp:1032
findport
static void findport(unsigned short port, char *serv, size_t servlen, int flags)
Definition: netsupp.cpp:925
KRF_inet_ntop
#define KRF_inet_ntop
Definition: netsupp.cpp:1030
sockaddr_in6
#define sockaddr_in6
Definition: netsupp.cpp:62
kde_getaddrinfo
int kde_getaddrinfo(const char *name, const char *service, const struct addrinfo *hint, struct kde_addrinfo **result)
Definition: netsupp.cpp:230
make_inet
static int make_inet(const char *name, int portnum, int protonum, struct addrinfo *p, const struct addrinfo *hint, struct addrinfo **result)
Definition: netsupp.cpp:556
kde_freeaddrinfo
void kde_freeaddrinfo(struct kde_addrinfo *ai)
Definition: netsupp.cpp:101
netsupp.h
inet_ntop
#define inet_ntop
Definition: netsupp.h:330
EAI_NONAME
#define EAI_NONAME
Definition: netsupp.h:233
EAI_SOCKTYPE
#define EAI_SOCKTYPE
Definition: netsupp.h:239
EAI_FAMILY
#define EAI_FAMILY
Definition: netsupp.h:224
NI_NAMEREQD
#define NI_NAMEREQD
Definition: netsupp.h:264
AI_NUMERICHOST
#define AI_NUMERICHOST
Definition: netsupp.h:194
EAI_MEMORY
#define EAI_MEMORY
Definition: netsupp.h:227
EAI_BADFLAGS
#define EAI_BADFLAGS
Definition: netsupp.h:218
NI_NUMERICHOST
#define NI_NUMERICHOST
Definition: netsupp.h:261
getaddrinfo
#define getaddrinfo
Definition: netsupp.h:304
EAI_AGAIN
#define EAI_AGAIN
Definition: netsupp.h:215
KAI_LOCALUNIX
#define KAI_LOCALUNIX
Definition: netsupp.h:142
EAI_SYSTEM
#define EAI_SYSTEM
Definition: netsupp.h:242
inet_pton
#define inet_pton
Definition: netsupp.h:319
KAI_SYSTEM
#define KAI_SYSTEM
Definition: netsupp.h:141
KDE_IN6_IS_ADDR_V4MAPPED
#define KDE_IN6_IS_ADDR_V4MAPPED(a)
Definition: netsupp.h:94
EAI_NODATA
#define EAI_NODATA
Definition: netsupp.h:230
AI_CANONNAME
#define AI_CANONNAME
Definition: netsupp.h:193
getnameinfo
#define getnameinfo
Definition: netsupp.h:306
EAI_SERVICE
#define EAI_SERVICE
Definition: netsupp.h:236
NI_DGRAM
#define NI_DGRAM
Definition: netsupp.h:265
EAI_FAIL
#define EAI_FAIL
Definition: netsupp.h:221
KDE_IN6_IS_ADDR_V4COMPAT
#define KDE_IN6_IS_ADDR_V4COMPAT(a)
Definition: netsupp.h:98
freeaddrinfo
#define freeaddrinfo
Definition: netsupp.h:305
AI_PASSIVE
#define AI_PASSIVE
Definition: netsupp.h:192
NI_NUMERICSERV
#define NI_NUMERICSERV
Definition: netsupp.h:262
addrinfo
Definition: netsupp.h:173
addrinfo::ai_addr
struct sockaddr * ai_addr
Definition: netsupp.h:179
addrinfo::ai_canonname
char * ai_canonname
Definition: netsupp.h:180
addrinfo::ai_socktype
int ai_socktype
Definition: netsupp.h:176
addrinfo::ai_protocol
int ai_protocol
Definition: netsupp.h:177
addrinfo::ai_addrlen
int ai_addrlen
Definition: netsupp.h:178
addrinfo::ai_next
struct addrinfo * ai_next
Definition: netsupp.h:181
addrinfo::ai_flags
int ai_flags
Definition: netsupp.h:174
addrinfo::ai_family
int ai_family
Definition: netsupp.h:175
kde_addrinfo
Definition: netsupp.h:156
kde_addrinfo::origin
int origin
Definition: netsupp.h:158
kde_addrinfo::data
struct addrinfo * data
Definition: netsupp.h:157
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs-4.14.38 API Reference

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

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