netsupp.cpp
来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· C++ 代码 · 共 1,244 行 · 第 1/3 页
CPP
1,244 行
/* * 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 <qglobal.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 == 1static 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: // Normal exit of the function if (err == 0) *result = res; else { 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?