diff options
Diffstat (limited to 'kdecore/netsupp.cpp')
-rw-r--r-- | kdecore/netsupp.cpp | 1237 |
1 files changed, 0 insertions, 1237 deletions
diff --git a/kdecore/netsupp.cpp b/kdecore/netsupp.cpp deleted file mode 100644 index 83aec8bc0..000000000 --- a/kdecore/netsupp.cpp +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * This file is part of the KDE libraries - * Copyright (C) 2000,2001 Thiago Macieira <thiago.macieira@kdemail.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - **/ - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <netinet/in.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <arpa/inet.h> - -#include <tqglobal.h> - -// This is so that, if addrinfo is defined, it doesn't clobber our definition -// It might be defined in the few cases in which we are replacing the system's -// broken getaddrinfo -#include <netdb.h> - -#include "config.h" -#include "kdebug.h" -#include "klocale.h" - -#ifndef IN6_IS_ADDR_V4MAPPED -#define NEED_IN6_TESTS -#endif -#undef CLOBBER_IN6 -#include "netsupp.h" - -#if defined(__hpux) || defined(_HPUX_SOURCE) -extern int h_errno; -#endif - -#include <kdemacros.h> - -#if !defined(kde_sockaddr_in6) -/* - * kde_sockaddr_in6 might have got defined even though we #undef'ed - * CLOBBER_IN6. This happens when we are compiling under --enable-final. - * However, in that case, if it was defined, that's because ksockaddr.cpp - * had it defined because sockaddr_in6 didn't exist, and so sockaddr_in6 - * exists and is our kde_sockaddr_in6 - */ -# define sockaddr_in6 kde_sockaddr_in6 -# define in6_addr kde_in6_addr -#endif - -#ifdef offsetof -#undef offsetof -#endif -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/* - * These constants tell the flags in KDE::resolverFlags - * The user could (but shouldn't) test the variable to know what kind of - * resolution is supported - */ -#define KRF_KNOWS_AF_INET6 0x01 /* if present, the code knows about AF_INET6 */ -#define KRF_USING_OWN_GETADDRINFO 0x02 /* if present, we are using our own getaddrinfo */ -#define KRF_USING_OWN_INET_NTOP 0x04 /* if present, we are using our own inet_ntop */ -#define KRF_USING_OWN_INET_PTON 0x08 /* if present, we are using our own inet_pton */ -#define KRF_CAN_RESOLVE_UNIX 0x100 /* if present, the resolver can resolve Unix sockets */ -#define KRF_CAN_RESOLVE_IPV4 0x200 /* if present, the resolver can resolve to IPv4 */ -#define KRF_CAN_RESOLVE_IPV6 0x400 /* if present, the resolver can resolve to IPv6 */ - - -static void dofreeaddrinfo(struct addrinfo *ai) -{ - while (ai) - { - struct addrinfo *ai2 = ai; - if (ai->ai_canonname != NULL) - free(ai->ai_canonname); - - if (ai->ai_addr != NULL) - free(ai->ai_addr); - - ai = ai->ai_next; - free(ai2); - } -} - -void kde_freeaddrinfo(struct kde_addrinfo *ai) -{ - if (ai->origin == KAI_LOCALUNIX) - { - struct addrinfo *p, *last = NULL; - /* We've added one AF_UNIX socket in here, to the - * tail of the linked list. We have to find it */ - for (p = ai->data; p; p = p->ai_next) - { - if (p->ai_family == AF_UNIX) - { - if (last) - { - last->ai_next = NULL; - freeaddrinfo(ai->data); - } - dofreeaddrinfo(p); - break; - } - last = p; - } - } - else - freeaddrinfo(ai->data); - - free(ai); -} - -static struct addrinfo* -make_unix(const char *name, const char *serv) -{ - const char *buf; - struct addrinfo *p; - struct sockaddr_un *_sun; - int len; - - p = (addrinfo*)malloc(sizeof(*p)); - if (p == NULL) - return NULL; - memset(p, 0, sizeof(*p)); - - if (name != NULL) - buf = name; - else - buf = serv; - - // Calculate length of the binary representation - len = strlen(buf) + offsetof(struct sockaddr_un, sun_path) + 1; - if (*buf != '/') - len += 5; // strlen("/tmp/"); - - _sun = (sockaddr_un*)malloc(len); - if (_sun == NULL) - { - // Oops - free(p); - return NULL; - } - - _sun->sun_family = AF_UNIX; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - _sun->sun_len = len; -# endif - if (*buf == '/') - *_sun->sun_path = '\0'; // empty it - else - strcpy(_sun->sun_path, "/tmp/"); - strcat(_sun->sun_path, buf); - - // Set the addrinfo - p->ai_family = AF_UNIX; - p->ai_addrlen = len; - p->ai_addr = (sockaddr*)_sun; - p->ai_canonname = strdup(buf); - - return p; -} - -// Ugh. I hate #ifdefs -// Anyways, here's what this does: -// KDE_IPV6_LOOKUP_MODE != 1, this function doesn't exist -// AF_INET6 not defined, we say there is no IPv6 stack -// otherwise, we try to create a socket. -// returns: 1 for IPv6 stack available, 2 for not available -#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1 -static int check_ipv6_stack() -{ -# ifndef AF_INET6 - return 2; // how can we check? -# else - if (getenv("KDE_NO_IPV6")) - return 2; - int fd = ::socket(AF_INET6, SOCK_STREAM, 0); - if (fd == -1) - return 2; - - ::close(fd); - return 1; -# endif -} -#endif - - -/* - * Reason for using this function: kde_getaddrinfo - * - * I decided to add this wrapper function for getaddrinfo - * and have this be called by KExtendedSocket instead of - * the real getaddrinfo so that we can make sure that the - * behavior is the desired one. - * - * Currently, the only "undesired" behavior is getaddrinfo - * not returning PF_UNIX sockets in some implementations. - * - * getaddrinfo and family are defined in POSIX 1003.1g - * (Protocol Independent Interfaces) and in RFC 2553 - * (Basic Socket Interface for IPv6). Whereas the RFC is ambiguosly - * vague whether this family of functions should return Internet - * sockets only or not, the name of the POSIX draft says - * otherwise: it should be independent of protocol. - * - * So, my interpretation is that they should return every - * kind of socket available and known and that's how I - * designed KExtendedSocket on top of it. - * - * That's why there's this wrapper, to make sure PF_UNIX - * sockets are returned when expected. - */ - -int kde_getaddrinfo(const char *name, const char *service, - const struct addrinfo* hint, - struct kde_addrinfo** result) -{ - struct kde_addrinfo* res; - struct addrinfo* p; - int err = EAI_SERVICE; -#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1 - // mode 1: do a check on whether we have an IPv6 stack - static int ipv6_stack = 0; // 0: unknown, 1: yes, 2: no -#endif - - // allocate memory for results - res = (kde_addrinfo*)malloc(sizeof(*res)); - if (res == NULL) - return EAI_MEMORY; - res->data = NULL; - res->origin = KAI_SYSTEM; // at first, it'll be only system data - - struct addrinfo* last = NULL; - - // Skip the getaddrinfo call and the ipv6 check for a UNIX socket. - if (hint && (hint->ai_family == PF_UNIX)) - { - if (service == NULL || *service == '\0') - goto out; // can't be Unix if no service was requested - - // Unix sockets must be localhost - // That is, either name is NULL or, if it's not, it must be empty, - // "*" or "localhost" - if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') || - strcmp("localhost", name) == 0)) - goto out; // isn't localhost - - goto do_unix; - } - -#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE != 0 -# if KDE_IPV6_LOOKUP_MODE == 1 - // mode 1: do a check on whether we have an IPv6 stack - if (ipv6_stack == 0) - ipv6_stack = check_ipv6_stack(); - - if (ipv6_stack == 2) - { -# endif - // here we have modes 1 and 2 (no lookups) - // this is shared code - struct addrinfo our_hint; - if (hint != NULL) - { - memcpy(&our_hint, hint, sizeof(our_hint)); - if (our_hint.ai_family == AF_UNSPEC) - our_hint.ai_family = AF_INET; - } - else - { - memset(&our_hint, 0, sizeof(our_hint)); - our_hint.ai_family = AF_INET; - } - - // do the actual resolution - err = getaddrinfo(name, service, &our_hint, &res->data); -# if KDE_IPV6_LOOKUP_MODE == 1 - } - else -# endif -#endif -#if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE != 2 - // do the IPV6 resolution - err = getaddrinfo(name, service, hint, &res->data); -#endif - - // Now we have to check whether the user could want a Unix socket - - if (service == NULL || *service == '\0') - goto out; // can't be Unix if no service was requested - - // Unix sockets must be localhost - // That is, either name is NULL or, if it's not, it must be empty, - // "*" or "localhost" - if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') || - strcmp("localhost", name) == 0)) - goto out; // isn't localhost - - // Unix sockets can only be returned if the user asked for a PF_UNSPEC - // or PF_UNIX socket type or gave us a NULL hint - if (hint != NULL && (hint->ai_family != PF_UNSPEC && hint->ai_family != PF_UNIX)) - goto out; // user doesn't want Unix - - // If we got here, then it means that the user might be expecting Unix - // sockets. The user wants a local socket, with a non-null service and - // has told us that they accept PF_UNIX sockets - // Check whether the system implementation returned Unix - if (err == 0) - for (p = res->data; p; p = p->ai_next) - { - last = p; // we have to find out which one is last anyways - if (p->ai_family == AF_UNIX) - // there is an Unix node - goto out; - } - - do_unix: - // So, give the user a PF_UNIX socket - p = make_unix(NULL, service); - if (p == NULL) - { - err = EAI_MEMORY; - goto out; - } - if (hint != NULL) - p->ai_socktype = hint->ai_socktype; - if (p->ai_socktype == 0) - p->ai_socktype = SOCK_STREAM; // default - - if (last) - last->ai_next = p; - else - res->data = p; - res->origin = KAI_LOCALUNIX; - *result = res; - return 0; - - out: - if (res->data != NULL) - freeaddrinfo(res->data); - free(res); - return err; -} - -#if defined(HAVE_GETADDRINFO) && !defined(HAVE_BROKEN_GETADDRINFO) - -#define KRF_getaddrinfo 0 -#define KRF_resolver 0 - -#else // !defined(HAVE_GETADDRINFO) || defined(HAVE_BROKEN_GETADDRINFO) - -#define KRF_getaddrinfo KRF_USING_OWN_GETADDRINFO -#define KRF_resolver KRF_CAN_RESOLVE_UNIX | KRF_CAN_RESOLVE_IPV4 - -/* - * No getaddrinfo() in this system. - * We shall provide our own - */ - -/** TODO - * Try and use gethostbyname2_r before gethostbyname2 and gethostbyname - */ -static int inet_lookup(const char *name, int portnum, int protonum, - struct addrinfo *p, const struct addrinfo *hint, - struct addrinfo** result) -{ - struct addrinfo *q; - struct hostent *h; - struct sockaddr **psa = NULL; - int len; - - // TODO - // Currently, this never resolves IPv6 (need gethostbyname2, etc.) -# ifdef AF_INET6 - if (hint->ai_family == AF_INET6) - { - if (p != NULL) - { - *result = p; - return 0; - } - return EAI_FAIL; - } -# endif - - q = (addrinfo*)malloc(sizeof(*q)); - if (q == NULL) - { - freeaddrinfo(p); - return EAI_MEMORY; - } - - h = gethostbyname(name); - if (h == NULL) - { - if (p != NULL) - { - // There already is a suitable result - *result = p; - return 0; - } - - switch (h_errno) - { - case HOST_NOT_FOUND: - return EAI_NONAME; - case TRY_AGAIN: - return EAI_AGAIN; - case NO_RECOVERY: - return EAI_FAIL; - case NO_ADDRESS: - return EAI_NODATA; - default: - // EH!? - return EAI_FAIL; - } - } - - // convert the hostent to addrinfo - if (h->h_addrtype == AF_INET && (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)) - len = sizeof(struct sockaddr_in); -# ifdef AF_INET6 - else if (h->h_addrtype == AF_INET6 && (hint->ai_family == AF_INET6 || - hint->ai_family == AF_UNSPEC)) - len = sizeof(struct sockaddr_in6); -# endif - else - { - // We don't know what to do with these addresses - // Or gethostbyname returned information we don't want - if (p != NULL) - { - *result = p; - return 0; - } - return EAI_NODATA; - } - - q->ai_flags = 0; - q->ai_family = h->h_addrtype; - q->ai_socktype = hint->ai_socktype; - q->ai_protocol = protonum; - q->ai_addrlen = len; - - q->ai_addr = (sockaddr*)malloc(len); - if (q->ai_addr == NULL) - { - free(q); - freeaddrinfo(p); - return EAI_MEMORY; - } - if (h->h_addrtype == AF_INET) - { - struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr; - sin->sin_family = AF_INET; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin->sin_len = sizeof(*sin); -# endif - sin->sin_port = portnum; - memcpy(&sin->sin_addr, h->h_addr, h->h_length); - } -# ifdef AF_INET6 - else if (h->h_addrtype == AF_INET6) - { - struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr; - sin6->sin6_family = AF_INET6; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin6->sin6_len = sizeof(*sin6); -# endif - sin6->sin6_port = portnum; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, h->h_addr, h->h_length); - sin6->sin6_scope_id = 0; - } -# endif - - if (hint->ai_flags & AI_CANONNAME) - q->ai_canonname = strdup(h->h_name); - else - q->ai_canonname = NULL; - - q->ai_next = p; - p = q; - - // cycle through the rest of the hosts; - for (psa = (sockaddr**)h->h_addr_list + 1; *psa; psa++) - { - q = (addrinfo*)malloc(sizeof(*q)); - if (q == NULL) - { - freeaddrinfo(p); - return EAI_MEMORY; - } - memcpy(q, p, sizeof(*q)); - - q->ai_addr = (sockaddr*)malloc(h->h_length); - if (q->ai_addr == NULL) - { - freeaddrinfo(p); - free(q); - return EAI_MEMORY; - } - if (h->h_addrtype == AF_INET) - { - struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr; - sin->sin_family = AF_INET; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin->sin_len = sizeof(*sin); -# endif - sin->sin_port = portnum; - memcpy(&sin->sin_addr, *psa, h->h_length); - } -# ifdef AF_INET6 - else if (h->h_addrtype == AF_INET6) - { - struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr; - sin6->sin6_family = AF_INET6; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin6->sin6_len = sizeof(*sin6); -# endif - sin6->sin6_port = portnum; - sin6->sin6_flowinfo = 0; - memcpy(&sin6->sin6_addr, *psa, h->h_length); - sin6->sin6_scope_id = 0; - } -# endif - - if (q->ai_canonname != NULL) - q->ai_canonname = strdup(q->ai_canonname); - - q->ai_next = p; - p = q; - } - - *result = p; - return 0; // Whew! Success! -} - -static int make_inet(const char *name, int portnum, int protonum, struct addrinfo *p, - const struct addrinfo *hint, struct addrinfo** result) -{ - struct addrinfo *q; - - do - { - // This 'do' is here just so that we can 'break' out of it - - if (name != NULL) - { - // first, try to use inet_pton before resolving - // it will catch IP addresses given without having to go to lookup - struct sockaddr_in *sin; - struct in_addr in; -# ifdef AF_INET6 - struct sockaddr_in6 *sin6; - struct in6_addr in6; - - if (hint->ai_family == AF_INET6 || (hint->ai_family == AF_UNSPEC && - strchr(name, ':') != NULL)) - { - // yes, this is IPv6 - if (inet_pton(AF_INET6, name, &in6) != 1) - { - if (hint->ai_flags & AI_NUMERICHOST) - { - freeaddrinfo(p); - return EAI_FAIL; - } - break; // not a numeric host - } - - sin6 = (sockaddr_in6*)malloc(sizeof(*sin6)); - if (sin6 == NULL) - { - freeaddrinfo(p); - return EAI_MEMORY; - } - memcpy(&sin6->sin6_addr, &in6, sizeof(in6)); - - if (strchr(name, '%') != NULL) - { - errno = 0; - sin6->sin6_scope_id = strtoul(strchr(name, '%') + 1, NULL, 10); - if (errno != 0) - sin6->sin6_scope_id = 0; // no interface - } - - q = (addrinfo*)malloc(sizeof(*q)); - if (q == NULL) - { - freeaddrinfo(p); - free(sin6); - return EAI_MEMORY; - } - - sin6->sin6_family = AF_INET6; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin6->sin6_len = sizeof(*sin6); -# endif - sin6->sin6_port = portnum; - sin6->sin6_flowinfo = 0; - - q->ai_flags = 0; - q->ai_family = AF_INET6; - q->ai_socktype = hint->ai_socktype; - q->ai_protocol = protonum; - q->ai_addrlen = sizeof(*sin6); - q->ai_canonname = NULL; - q->ai_addr = (sockaddr*)sin6; - q->ai_next = p; - - *result = q; - return 0; // success! - } -# endif // AF_INET6 - - if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC) - { - // This has to be IPv4 - if (inet_pton(AF_INET, name, &in) != 1) - { - if (hint->ai_flags & AI_NUMERICHOST) - { - freeaddrinfo(p); - return EAI_FAIL; // invalid, I guess - } - break; // not a numeric host, do lookup - } - - sin = (sockaddr_in*)malloc(sizeof(*sin)); - if (sin == NULL) - { - freeaddrinfo(p); - return EAI_MEMORY; - } - - q = (addrinfo*)malloc(sizeof(*q)); - if (q == NULL) - { - freeaddrinfo(p); - free(sin); - return EAI_MEMORY; - } - - sin->sin_family = AF_INET; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin->sin_len = sizeof(*sin); -# endif - sin->sin_port = portnum; - sin->sin_addr = in; - - q->ai_flags = 0; - q->ai_family = AF_INET; - q->ai_socktype = hint->ai_socktype; - q->ai_protocol = protonum; - q->ai_addrlen = sizeof(*sin); - q->ai_canonname = NULL; - q->ai_addr = (sockaddr*)sin; - q->ai_next = p; - *result = q; - return 0; - } - - // Eh, what!? - // One of the two above has to have matched - kdError() << "I wasn't supposed to get here!"; - } - } while (false); - - // This means localhost - if (name == NULL) - { - struct sockaddr_in *sin = (sockaddr_in*)malloc(sizeof(*sin)); -# ifdef AF_INET6 - struct sockaddr_in6 *sin6; -# endif - - if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC) - { - if (sin == NULL) - { - free(sin); - freeaddrinfo(p); - return EAI_MEMORY; - } - - // Do IPv4 first - q = (addrinfo*)malloc(sizeof(*q)); - if (q == NULL) - { - free(sin); - freeaddrinfo(p); - return EAI_MEMORY; - } - - sin->sin_family = AF_INET; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin->sin_len = sizeof(*sin); -# endif - sin->sin_port = portnum; - if (hint->ai_flags & AI_PASSIVE) - *(TQ_UINT32*)&sin->sin_addr = INADDR_ANY; - else - *(TQ_UINT32*)&sin->sin_addr = htonl(INADDR_LOOPBACK); - q->ai_flags = 0; - q->ai_family = AF_INET; - q->ai_socktype = hint->ai_socktype; - q->ai_protocol = protonum; - q->ai_addrlen = sizeof(*sin); - q->ai_canonname = NULL; - q->ai_addr = (sockaddr*)sin; - q->ai_next = p; - p = q; - } - -# ifdef AF_INET6 - // Try now IPv6 - - if (hint->ai_family == AF_INET6 || hint->ai_family == AF_UNSPEC) - { - sin6 = (sockaddr_in6*)malloc(sizeof(*sin6)); - q = (addrinfo*)malloc(sizeof(*q)); - if (q == NULL || sin6 == NULL) - { - free(sin6); - free(q); - freeaddrinfo(p); - return EAI_MEMORY; - } - - sin6->sin6_family = AF_INET6; -# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin6->sin6_len = sizeof(*sin6); -# endif - sin6->sin6_port = portnum; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - - // We don't want to use in6addr_loopback and in6addr_any - memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); - if ((hint->ai_flags & AI_PASSIVE) == 0) - ((char*)&sin6->sin6_addr)[15] = 1; - - q->ai_flags = 0; - q->ai_family = AF_INET6; - q->ai_socktype = hint->ai_socktype; - q->ai_protocol = protonum; - q->ai_addrlen = sizeof(*sin6); - q->ai_canonname = NULL; - q->ai_addr = (sockaddr*)sin6; - q->ai_next = p; - p = q; - } - -# endif // AF_INET6 - - *result = p; - return 0; // success! - } - - return inet_lookup(name, portnum, protonum, p, hint, result); -} - - -int getaddrinfo(const char *name, const char *serv, - const struct addrinfo* hint, - struct addrinfo** result) -{ - unsigned short portnum; // remember to store in network byte order - int protonum = IPPROTO_TCP; - const char *proto = "tcp"; - struct addrinfo *p = NULL; - - // Sanity checks: - if (hint == NULL || result == NULL) - return EAI_BADFLAGS; - if (hint->ai_family != AF_UNSPEC && hint->ai_family != AF_UNIX && - hint->ai_family != AF_INET -# ifdef AF_INET6 - && hint->ai_family != AF_INET6 -# endif - ) - return EAI_FAMILY; - if (hint->ai_socktype != 0 && hint->ai_socktype != SOCK_STREAM && - hint->ai_socktype != SOCK_DGRAM) - return EAI_SOCKTYPE; - - // Treat hostname of "*" as NULL, which means localhost - if (name != NULL && ((*name == '*' && name[1] == '\0') || *name == '\0')) - name = NULL; - // Treat service of "*" as NULL, which I guess means no port (0) - if (serv != NULL && ((*serv == '*' && serv[1] == '\0') || *serv == '\0')) - serv = NULL; - - if (name == NULL && serv == NULL) // what the hell do you want? - return EAI_NONAME; - - // This is just to make it easier - if (name != NULL && strcmp(name, "localhost") == 0) - name = NULL; - - // First, check for a Unix socket - // family must be either AF_UNIX or AF_UNSPEC - // either of name or serv must be set, the other must be NULL or empty - if (hint->ai_family == AF_UNIX || hint->ai_family == AF_UNSPEC) - { - if (name != NULL && serv != NULL) - { - // This is not allowed - if (hint->ai_family == AF_UNIX) - return EAI_BADFLAGS; - } - else - { - p = make_unix(name, serv); - if (p == NULL) - return EAI_MEMORY; - - p->ai_socktype = hint->ai_socktype; - // If the name/service started with a slash, then this *IS* - // only a Unix socket. Return. - if (hint->ai_family == AF_UNIX || ((name != NULL && *name == '/') || - (serv != NULL && *serv == '/'))) - { - *result = p; - return 0; // successful lookup - } - } - } - - // Lookup the service name, if required - if (serv != NULL) - { - char *tail; - struct servent *sent; - - portnum = htons((unsigned)strtoul(serv, &tail, 10)); - if (*tail != '\0') - { - // not a number. We have to do the lookup - if (hint->ai_socktype == SOCK_DGRAM) - { - proto = "udp"; - protonum = IPPROTO_UDP; - } - - sent = getservbyname(serv, proto); - if (sent == NULL) // no service? - { - if (p == NULL) - return EAI_NONAME; - else - return 0; // a Unix socket available - } - - portnum = sent->s_port; - } - } - else - portnum = 0; // no port number - - return make_inet(name, portnum, protonum, p, hint, result); -} - -void freeaddrinfo(struct addrinfo *p) -{ - dofreeaddrinfo(p); -} - -char *gai_strerror(int errorcode) -{ - static const char * const messages[] = - { - I18N_NOOP("no error"), // 0 - I18N_NOOP("address family for nodename not supported"), // EAI_ADDRFAMILY - I18N_NOOP("temporary failure in name resolution"), // EAI_AGAIN - I18N_NOOP("invalid value for 'ai_flags'"), // EAI_BADFLAGS - I18N_NOOP("non-recoverable failure in name resolution"), // EAI_FAIL - I18N_NOOP("'ai_family' not supported"), // EAI_FAMILY - I18N_NOOP("memory allocation failure"), // EAI_MEMORY - I18N_NOOP("no address associated with nodename"), // EAI_NODATA - I18N_NOOP("name or service not known"), // EAI_NONAME - I18N_NOOP("servname not supported for ai_socktype"), // EAI_SERVICE - I18N_NOOP("'ai_socktype' not supported"), // EAI_SOCKTYPE - I18N_NOOP("system error") // EAI_SYSTEM - }; - - if (errorcode > EAI_SYSTEM || errorcode < 0) - return NULL; - - static char buffer[200]; - strcpy(buffer, i18n(messages[errorcode]).local8Bit()); - return buffer; -} - -static void findport(unsigned short port, char *serv, size_t servlen, int flags) -{ - if (serv == NULL) - return; - - if ((flags & NI_NUMERICSERV) == 0) - { - struct servent *sent; - sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp"); - if (sent != NULL && servlen > strlen(sent->s_name)) - { - strcpy(serv, sent->s_name); - return; - } - } - - snprintf(serv, servlen, "%u", ntohs(port)); -} - -int getnameinfo(const struct sockaddr *sa, ksocklen_t salen, - char *host, size_t hostlen, char *serv, size_t servlen, - int flags) -{ - union - { - const sockaddr *sa; - const sockaddr_un *_sun; - const sockaddr_in *sin; - const sockaddr_in6 *sin6; - } s; - - if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0)) - return 1; - - s.sa = sa; - if (s.sa->sa_family == AF_UNIX) - { - if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1) - return 1; // invalid socket - - if (servlen && serv != NULL) - *serv = '\0'; - if (host != NULL && hostlen > strlen(s._sun->sun_path)) - strcpy(host, s._sun->sun_path); - - return 0; - } - else if (s.sa->sa_family == AF_INET) - { - if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr)) - return 1; // invalid socket - - if (flags & NI_NUMERICHOST) - inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen); - else - { - // have to do lookup - struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr), - AF_INET); - if (h == NULL && flags & NI_NAMEREQD) - return 1; - else if (h == NULL) - inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen); - else if (host != NULL && hostlen > strlen(h->h_name)) - strcpy(host, h->h_name); - else - return 1; // error - } - - findport(s.sin->sin_port, serv, servlen, flags); - } -# ifdef AF_INET6 - else if (s.sa->sa_family == AF_INET6) - { - if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr)) - return 1; // invalid socket - - if (flags & NI_NUMERICHOST) - inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen); - else - { - // have to do lookup - struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr), - AF_INET6); - if (h == NULL && flags & NI_NAMEREQD) - return 1; - else if (h == NULL) - inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen); - else if (host != NULL && hostlen > strlen(h->h_name)) - strcpy(host, h->h_name); - else - return 1; // error - } - - findport(s.sin6->sin6_port, serv, servlen, flags); - } -# endif // AF_INET6 - - return 1; // invalid family -} - -#endif // HAVE_GETADDRINFO - -#ifndef HAVE_INET_NTOP - -#define KRF_inet_ntop KRF_USING_OWN_INET_NTOP - -static void add_dwords(char *buf, TQ_UINT16 *dw, int count) -{ - int i = 1; - sprintf(buf + strlen(buf), "%x", ntohs(dw[0])); - while (--count) - sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++])); -} - -const char* inet_ntop(int af, const void *cp, char *buf, size_t len) -{ - char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1]; - TQ_UINT8 *data = (TQ_UINT8*)cp; - - if (af == AF_INET) - { - sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]); - - if (len > strlen(buf2)) - { - strcpy(buf, buf2); - return buf; - } - - errno = ENOSPC; - return NULL; // failed - } - -# ifdef AF_INET6 - if (af == AF_INET6) - { - TQ_UINT16 *p = (TQ_UINT16*)data; - TQ_UINT16 *longest = NULL, *cur = NULL; - int longest_length = 0, cur_length; - int i; - - if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p)) - sprintf(buf2, "::%s%u.%u.%u.%u", - KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "", - buf[12], buf[13], buf[14], buf[15]); - else - { - // find the longest sequence of zeroes - for (i = 0; i < 8; i++) - if (cur == NULL && p[i] == 0) - { - // a zero, start the sequence - cur = p + i; - cur_length = 1; - } - else if (cur != NULL && p[i] == 0) - // part of the sequence - cur_length++; - else if (cur != NULL && p[i] != 0) - { - // end of the sequence - if (cur_length > longest_length) - { - longest_length = cur_length; - longest = cur; - } - cur = NULL; // restart sequence - } - if (cur != NULL && cur_length > longest_length) - { - longest_length = cur_length; - longest = cur; - } - - if (longest_length > 1) - { - // We have a candidate - buf2[0] = '\0'; - if (longest != p) - add_dwords(buf2, p, longest - p); - strcat(buf2, "::"); - if (longest + longest_length < p + 8) - add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length); - } - else - { - // Nope, no candidate - buf2[0] = '\0'; - add_dwords(buf2, p, 8); - } - } - - if (strlen(buf2) < len) - { - strcpy(buf, buf2); - return buf; - } - - errno = ENOSPC; - return NULL; - } -# endif - - errno = EAFNOSUPPORT; - return NULL; // a family we don't know about -} - -#else // HAVE_INET_NTOP - -#define KRF_inet_ntop 0 - -#endif // HAVE_INET_NTOP - -#ifndef HAVE_INET_PTON - -#define KRF_inet_pton KRF_USING_OWN_INET_PTON -int inet_pton(int af, const char *cp, void *buf) -{ - if (af == AF_INET) - { - // Piece of cake - unsigned p[4]; - unsigned char *q = (unsigned char*)buf; - if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4) - return 0; - - if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff) - return 0; - - q[0] = p[0]; - q[1] = p[1]; - q[2] = p[2]; - q[3] = p[3]; - - return 1; - } - -# ifdef AF_INET6 - else if (af == AF_INET6) - { - TQ_UINT16 addr[8]; - const char *p = cp; - int n = 0, start = 8; - bool has_v4 = strchr(p, '.') != NULL; - - memset(addr, 0, sizeof(addr)); - - if (*p == '\0' || p[1] == '\0') - return 0; // less than 2 chars is not valid - - if (*p == ':' && p[1] == ':') - { - start = 0; - p += 2; - } - while (*p) - { - if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0) - { - // successful v4 convertion - addr[n] = ntohs(addr[n]); - n++; - addr[n] = ntohs(addr[n]); - n++; - break; - } - if (sscanf(p, "%hx", addr + n++) != 1) - return 0; - - while (*p && *p != ':') - p++; - if (!*p) - break; - p++; - - if (*p == ':') // another ':'? - { - if (start != 8) - return 0; // two :: were found - start = n; - p++; - } - } - - // if start is not 8, then a "::" was found at word 'start' - // n is the number of converted words - // n == 8 means everything was converted and no moving is necessary - // n < 8 means that we have to move n - start words 8 - n words to the right - if (start == 8 && n != 8) - return 0; // bad conversion - memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(TQ_UINT16)); - memset(addr + start, 0, (8 - n) * sizeof(TQ_UINT16)); - - // check the byte order - // The compiler should optimise this out in big endian machines - if (htons(0x1234) != 0x1234) - for (n = 0; n < 8; n++) - addr[n] = htons(addr[n]); - - memcpy(buf, addr, sizeof(addr)); - return 1; - } -# endif - - errno = EAFNOSUPPORT; - return -1; // unknown family -} - -#else // HAVE_INET_PTON - -#define KRF_inet_pton 0 - -#endif // HAVE_INET_PTON - -#ifdef AF_INET6 -# define KRF_afinet6 KRF_KNOWS_AF_INET6 -#else -# define KRF_afinet6 0 -#endif - -namespace KDE -{ - /** @internal */ - extern const int KDE_EXPORT resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton; -} |