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 + -
显示快捷键?