+++ /dev/null
-/*\r
- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.\r
- * All rights reserved.\r
- *\r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions\r
- * are met:\r
- * 1. Redistributions of source code must retain the above copyright\r
- * notice, this list of conditions and the following disclaimer.\r
- * 2. Redistributions in binary form must reproduce the above copyright\r
- * notice, this list of conditions and the following disclaimer in the\r
- * documentation and/or other materials provided with the distribution.\r
- * 3. Neither the name of the project nor the names of its contributors\r
- * may be used to endorse or promote products derived from this software\r
- * without specific prior written permission.\r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND\r
- * GAI_ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE\r
- * FOR GAI_ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
- * HOWEVER CAUSED AND ON GAI_ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN GAI_ANY WAY\r
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
- * SUCH DAMAGE.\r
- */\r
-\r
-/*\r
- * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.\r
- *\r
- * Issues to be discussed:\r
- * - Thread safe-ness must be checked.\r
- * - Return values. There are nonstandard return values defined and used\r
- * in the source code. This is because RFC2133 is silent about which error\r
- * code must be returned for which situation.\r
- * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.\r
- */\r
-\r
-#if 0\r
-#include <sys/types.h>\r
-#include <sys/param.h>\r
-#include <sys/sysctl.h>\r
-#include <sys/socket.h>\r
-#include <netinet/in.h>\r
-#include <arpa/inet.h>\r
-#include <arpa/nameser.h>\r
-#include <netdb.h>\r
-#include <resolv.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include <stddef.h>\r
-#include <ctype.h>\r
-#include <unistd.h>\r
-\r
-#include "addrinfo.h"\r
-#endif\r
-\r
-#if defined(__KAME__) && defined(ENABLE_IPV6)\r
-# define FAITH\r
-#endif\r
-\r
-#define SUCCESS 0\r
-#define GAI_ANY 0\r
-#define YES 1\r
-#define NO 0\r
-\r
-#ifdef FAITH\r
-static int translate = NO;\r
-static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;\r
-#endif\r
-\r
-static const char in_addrany[] = { 0, 0, 0, 0 };\r
-static const char in6_addrany[] = {\r
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
-};\r
-static const char in_loopback[] = { 127, 0, 0, 1 };\r
-static const char in6_loopback[] = {\r
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1\r
-};\r
-\r
-struct sockinet {\r
- u_char si_len;\r
- u_char si_family;\r
- u_short si_port;\r
-};\r
-\r
-static struct gai_afd {\r
- int a_af;\r
- int a_addrlen;\r
- int a_socklen;\r
- int a_off;\r
- const char *a_addrany;\r
- const char *a_loopback;\r
-} gai_afdl [] = {\r
-#ifdef ENABLE_IPV6\r
-#define N_INET6 0\r
- {PF_INET6, sizeof(struct in6_addr),\r
- sizeof(struct sockaddr_in6),\r
- offsetof(struct sockaddr_in6, sin6_addr),\r
- in6_addrany, in6_loopback},\r
-#define N_INET 1\r
-#else\r
-#define N_INET 0\r
-#endif\r
- {PF_INET, sizeof(struct in_addr),\r
- sizeof(struct sockaddr_in),\r
- offsetof(struct sockaddr_in, sin_addr),\r
- in_addrany, in_loopback},\r
- {0, 0, 0, 0, NULL, NULL},\r
-};\r
-\r
-#ifdef ENABLE_IPV6\r
-#define PTON_MAX 16\r
-#else\r
-#define PTON_MAX 4\r
-#endif\r
-\r
-#ifndef IN_MULTICAST\r
-#define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U)\r
-#endif\r
-\r
-#ifndef IN_EXPERIMENTAL\r
-#define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U)\r
-#endif\r
-\r
-#ifndef IN_LOOPBACKNET\r
-#define IN_LOOPBACKNET 127\r
-#endif\r
-\r
-static int get_name Py_PROTO((const char *, struct gai_afd *,\r
- struct addrinfo **, char *, struct addrinfo *,\r
- int));\r
-static int get_addr Py_PROTO((const char *, int, struct addrinfo **,\r
- struct addrinfo *, int));\r
-static int str_isnumber Py_PROTO((const char *));\r
-\r
-static char *ai_errlist[] = {\r
- "success.",\r
- "address family for hostname not supported.", /* EAI_ADDRFAMILY */\r
- "temporary failure in name resolution.", /* EAI_AGAIN */\r
- "invalid value for ai_flags.", /* EAI_BADFLAGS */\r
- "non-recoverable failure in name resolution.", /* EAI_FAIL */\r
- "ai_family not supported.", /* EAI_FAMILY */\r
- "memory allocation failure.", /* EAI_MEMORY */\r
- "no address associated with hostname.", /* EAI_NODATA */\r
- "hostname nor servname provided, or not known.",/* EAI_NONAME */\r
- "servname not supported for ai_socktype.", /* EAI_SERVICE */\r
- "ai_socktype not supported.", /* EAI_SOCKTYPE */\r
- "system error returned in errno.", /* EAI_SYSTEM */\r
- "invalid value for hints.", /* EAI_BADHINTS */\r
- "resolved protocol is unknown.", /* EAI_PROTOCOL */\r
- "unknown error.", /* EAI_MAX */\r
-};\r
-\r
-#define GET_CANONNAME(ai, str) \\r
-if (pai->ai_flags & AI_CANONNAME) {\\r
- if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\\r
- strcpy((ai)->ai_canonname, (str));\\r
- } else {\\r
- error = EAI_MEMORY;\\r
- goto free;\\r
- }\\r
-}\r
-\r
-#ifdef HAVE_SOCKADDR_SA_LEN\r
-#define GET_AI(ai, gai_afd, addr, port) {\\r
- char *p;\\r
- if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\\r
- ((gai_afd)->a_socklen)))\\r
- == NULL) goto free;\\r
- memcpy(ai, pai, sizeof(struct addrinfo));\\r
- (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\\r
- memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\\r
- (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\\r
- (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\\r
- ((struct sockinet *)(ai)->ai_addr)->si_port = port;\\r
- p = (char *)((ai)->ai_addr);\\r
- memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\\r
-}\r
-#else\r
-#define GET_AI(ai, gai_afd, addr, port) {\\r
- char *p;\\r
- if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\\r
- ((gai_afd)->a_socklen)))\\r
- == NULL) goto free;\\r
- memcpy(ai, pai, sizeof(struct addrinfo));\\r
- (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\\r
- memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\\r
- (ai)->ai_addrlen = (gai_afd)->a_socklen;\\r
- (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\\r
- ((struct sockinet *)(ai)->ai_addr)->si_port = port;\\r
- p = (char *)((ai)->ai_addr);\\r
- memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\\r
-}\r
-#endif\r
-\r
-#define ERR(err) { error = (err); goto bad; }\r
-\r
-char *\r
-gai_strerror(int ecode)\r
-{\r
- if (ecode < 0 || ecode > EAI_MAX)\r
- ecode = EAI_MAX;\r
- return ai_errlist[ecode];\r
-}\r
-\r
-void\r
-freeaddrinfo(struct addrinfo *ai)\r
-{\r
- struct addrinfo *next;\r
-\r
- do {\r
- next = ai->ai_next;\r
- if (ai->ai_canonname)\r
- free(ai->ai_canonname);\r
- /* no need to free(ai->ai_addr) */\r
- free(ai);\r
- } while ((ai = next) != NULL);\r
-}\r
-\r
-static int\r
-str_isnumber(const char *p)\r
-{\r
- unsigned char *q = (unsigned char *)p;\r
- while (*q) {\r
- if (! isdigit(*q))\r
- return NO;\r
- q++;\r
- }\r
- return YES;\r
-}\r
-\r
-int\r
-getaddrinfo(const char*hostname, const char*servname,\r
- const struct addrinfo *hints, struct addrinfo **res)\r
-{\r
- struct addrinfo sentinel;\r
- struct addrinfo *top = NULL;\r
- struct addrinfo *cur;\r
- int i, error = 0;\r
- char pton[PTON_MAX];\r
- struct addrinfo ai;\r
- struct addrinfo *pai;\r
- u_short port;\r
-\r
-#ifdef FAITH\r
- static int firsttime = 1;\r
-\r
- if (firsttime) {\r
- /* translator hack */\r
- {\r
- char *q = getenv("GAI");\r
- if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)\r
- translate = YES;\r
- }\r
- firsttime = 0;\r
- }\r
-#endif\r
-\r
- /* initialize file static vars */\r
- sentinel.ai_next = NULL;\r
- cur = &sentinel;\r
- pai = &ai;\r
- pai->ai_flags = 0;\r
- pai->ai_family = PF_UNSPEC;\r
- pai->ai_socktype = GAI_ANY;\r
- pai->ai_protocol = GAI_ANY;\r
- pai->ai_addrlen = 0;\r
- pai->ai_canonname = NULL;\r
- pai->ai_addr = NULL;\r
- pai->ai_next = NULL;\r
- port = GAI_ANY;\r
-\r
- if (hostname == NULL && servname == NULL)\r
- return EAI_NONAME;\r
- if (hints) {\r
- /* error check for hints */\r
- if (hints->ai_addrlen || hints->ai_canonname ||\r
- hints->ai_addr || hints->ai_next)\r
- ERR(EAI_BADHINTS); /* xxx */\r
- if (hints->ai_flags & ~AI_MASK)\r
- ERR(EAI_BADFLAGS);\r
- switch (hints->ai_family) {\r
- case PF_UNSPEC:\r
- case PF_INET:\r
-#ifdef ENABLE_IPV6\r
- case PF_INET6:\r
-#endif\r
- break;\r
- default:\r
- ERR(EAI_FAMILY);\r
- }\r
- memcpy(pai, hints, sizeof(*pai));\r
- switch (pai->ai_socktype) {\r
- case GAI_ANY:\r
- switch (pai->ai_protocol) {\r
- case GAI_ANY:\r
- break;\r
- case IPPROTO_UDP:\r
- pai->ai_socktype = SOCK_DGRAM;\r
- break;\r
- case IPPROTO_TCP:\r
- pai->ai_socktype = SOCK_STREAM;\r
- break;\r
- default:\r
- pai->ai_socktype = SOCK_RAW;\r
- break;\r
- }\r
- break;\r
- case SOCK_RAW:\r
- break;\r
- case SOCK_DGRAM:\r
- if (pai->ai_protocol != IPPROTO_UDP &&\r
- pai->ai_protocol != GAI_ANY)\r
- ERR(EAI_BADHINTS); /*xxx*/\r
- pai->ai_protocol = IPPROTO_UDP;\r
- break;\r
- case SOCK_STREAM:\r
- if (pai->ai_protocol != IPPROTO_TCP &&\r
- pai->ai_protocol != GAI_ANY)\r
- ERR(EAI_BADHINTS); /*xxx*/\r
- pai->ai_protocol = IPPROTO_TCP;\r
- break;\r
- default:\r
- ERR(EAI_SOCKTYPE);\r
- /* unreachable */\r
- }\r
- }\r
-\r
- /*\r
- * service port\r
- */\r
- if (servname) {\r
- if (str_isnumber(servname)) {\r
- if (pai->ai_socktype == GAI_ANY) {\r
- /* caller accept *GAI_ANY* socktype */\r
- pai->ai_socktype = SOCK_DGRAM;\r
- pai->ai_protocol = IPPROTO_UDP;\r
- }\r
- port = htons((u_short)atoi(servname));\r
- } else {\r
- struct servent *sp;\r
- char *proto;\r
-\r
- proto = NULL;\r
- switch (pai->ai_socktype) {\r
- case GAI_ANY:\r
- proto = NULL;\r
- break;\r
- case SOCK_DGRAM:\r
- proto = "udp";\r
- break;\r
- case SOCK_STREAM:\r
- proto = "tcp";\r
- break;\r
- default:\r
- fprintf(stderr, "panic!\n");\r
- break;\r
- }\r
- if ((sp = getservbyname(servname, proto)) == NULL)\r
- ERR(EAI_SERVICE);\r
- port = sp->s_port;\r
- if (pai->ai_socktype == GAI_ANY) {\r
- if (strcmp(sp->s_proto, "udp") == 0) {\r
- pai->ai_socktype = SOCK_DGRAM;\r
- pai->ai_protocol = IPPROTO_UDP;\r
- } else if (strcmp(sp->s_proto, "tcp") == 0) {\r
- pai->ai_socktype = SOCK_STREAM;\r
- pai->ai_protocol = IPPROTO_TCP;\r
- } else\r
- ERR(EAI_PROTOCOL); /*xxx*/\r
- }\r
- }\r
- }\r
-\r
- /*\r
- * hostname == NULL.\r
- * passive socket -> anyaddr (0.0.0.0 or ::)\r
- * non-passive socket -> localhost (127.0.0.1 or ::1)\r
- */\r
- if (hostname == NULL) {\r
- struct gai_afd *gai_afd;\r
-\r
- for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {\r
- if (!(pai->ai_family == PF_UNSPEC\r
- || pai->ai_family == gai_afd->a_af)) {\r
- continue;\r
- }\r
-\r
- if (pai->ai_flags & AI_PASSIVE) {\r
- GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);\r
- /* xxx meaningless?\r
- * GET_CANONNAME(cur->ai_next, "anyaddr");\r
- */\r
- } else {\r
- GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,\r
- port);\r
- /* xxx meaningless?\r
- * GET_CANONNAME(cur->ai_next, "localhost");\r
- */\r
- }\r
- cur = cur->ai_next;\r
- }\r
- top = sentinel.ai_next;\r
- if (top)\r
- goto good;\r
- else\r
- ERR(EAI_FAMILY);\r
- }\r
-\r
- /* hostname as numeric name */\r
- for (i = 0; gai_afdl[i].a_af; i++) {\r
- if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {\r
- u_long v4a;\r
-#ifdef ENABLE_IPV6\r
- u_char pfx;\r
-#endif\r
-\r
- switch (gai_afdl[i].a_af) {\r
- case AF_INET:\r
- v4a = ((struct in_addr *)pton)->s_addr;\r
- v4a = ntohl(v4a);\r
- if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))\r
- pai->ai_flags &= ~AI_CANONNAME;\r
- v4a >>= IN_CLASSA_NSHIFT;\r
- if (v4a == 0 || v4a == IN_LOOPBACKNET)\r
- pai->ai_flags &= ~AI_CANONNAME;\r
- break;\r
-#ifdef ENABLE_IPV6\r
- case AF_INET6:\r
- pfx = ((struct in6_addr *)pton)->s6_addr8[0];\r
- if (pfx == 0 || pfx == 0xfe || pfx == 0xff)\r
- pai->ai_flags &= ~AI_CANONNAME;\r
- break;\r
-#endif\r
- }\r
-\r
- if (pai->ai_family == gai_afdl[i].a_af ||\r
- pai->ai_family == PF_UNSPEC) {\r
- if (! (pai->ai_flags & AI_CANONNAME)) {\r
- GET_AI(top, &gai_afdl[i], pton, port);\r
- goto good;\r
- }\r
- /*\r
- * if AI_CANONNAME and if reverse lookup\r
- * fail, return ai anyway to pacify\r
- * calling application.\r
- *\r
- * XXX getaddrinfo() is a name->address\r
- * translation function, and it looks strange\r
- * that we do addr->name translation here.\r
- */\r
- get_name(pton, &gai_afdl[i], &top, pton, pai, port);\r
- goto good;\r
- } else\r
- ERR(EAI_FAMILY); /*xxx*/\r
- }\r
- }\r
-\r
- if (pai->ai_flags & AI_NUMERICHOST)\r
- ERR(EAI_NONAME);\r
-\r
- /* hostname as alphabetical name */\r
- error = get_addr(hostname, pai->ai_family, &top, pai, port);\r
- if (error == 0) {\r
- if (top) {\r
- good:\r
- *res = top;\r
- return SUCCESS;\r
- } else\r
- error = EAI_FAIL;\r
- }\r
- free:\r
- if (top)\r
- freeaddrinfo(top);\r
- bad:\r
- *res = NULL;\r
- return error;\r
-}\r
-\r
-static int\r
-get_name(addr, gai_afd, res, numaddr, pai, port0)\r
- const char *addr;\r
- struct gai_afd *gai_afd;\r
- struct addrinfo **res;\r
- char *numaddr;\r
- struct addrinfo *pai;\r
- int port0;\r
-{\r
- u_short port = port0 & 0xffff;\r
- struct hostent *hp;\r
- struct addrinfo *cur;\r
- int error = 0;\r
-#ifdef ENABLE_IPV6\r
- int h_error;\r
-#endif\r
-\r
-#ifdef ENABLE_IPV6\r
- hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);\r
-#else\r
- hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);\r
-#endif\r
- if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {\r
- GET_AI(cur, gai_afd, hp->h_addr_list[0], port);\r
- GET_CANONNAME(cur, hp->h_name);\r
- } else\r
- GET_AI(cur, gai_afd, numaddr, port);\r
-\r
-#ifdef ENABLE_IPV6\r
- if (hp)\r
- freehostent(hp);\r
-#endif\r
- *res = cur;\r
- return SUCCESS;\r
- free:\r
- if (cur)\r
- freeaddrinfo(cur);\r
-#ifdef ENABLE_IPV6\r
- if (hp)\r
- freehostent(hp);\r
-#endif\r
- /* bad: */\r
- *res = NULL;\r
- return error;\r
-}\r
-\r
-static int\r
-get_addr(hostname, af, res, pai, port0)\r
- const char *hostname;\r
- int af;\r
- struct addrinfo **res;\r
- struct addrinfo *pai;\r
- int port0;\r
-{\r
- u_short port = port0 & 0xffff;\r
- struct addrinfo sentinel;\r
- struct hostent *hp;\r
- struct addrinfo *top, *cur;\r
- struct gai_afd *gai_afd;\r
- int i, error = 0, h_error;\r
- char *ap;\r
-\r
- top = NULL;\r
- sentinel.ai_next = NULL;\r
- cur = &sentinel;\r
-#ifdef ENABLE_IPV6\r
- if (af == AF_UNSPEC) {\r
- hp = getipnodebyname(hostname, AF_INET6,\r
- AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);\r
- } else\r
- hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);\r
-#else\r
- hp = gethostbyname(hostname);\r
- h_error = h_errno;\r
-#endif\r
- if (hp == NULL) {\r
- switch (h_error) {\r
- case HOST_NOT_FOUND:\r
- case NO_DATA:\r
- error = EAI_NODATA;\r
- break;\r
- case TRY_AGAIN:\r
- error = EAI_AGAIN;\r
- break;\r
- case NO_RECOVERY:\r
- default:\r
- error = EAI_FAIL;\r
- break;\r
- }\r
- goto free;\r
- }\r
-\r
- if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||\r
- (hp->h_addr_list[0] == NULL)) {\r
- error = EAI_FAIL;\r
- goto free;\r
- }\r
-\r
- for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {\r
- switch (af) {\r
-#ifdef ENABLE_IPV6\r
- case AF_INET6:\r
- gai_afd = &gai_afdl[N_INET6];\r
- break;\r
-#endif\r
-#ifndef ENABLE_IPV6\r
- default: /* AF_UNSPEC */\r
-#endif\r
- case AF_INET:\r
- gai_afd = &gai_afdl[N_INET];\r
- break;\r
-#ifdef ENABLE_IPV6\r
- default: /* AF_UNSPEC */\r
- if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {\r
- ap += sizeof(struct in6_addr) -\r
- sizeof(struct in_addr);\r
- gai_afd = &gai_afdl[N_INET];\r
- } else\r
- gai_afd = &gai_afdl[N_INET6];\r
- break;\r
-#endif\r
- }\r
-#ifdef FAITH\r
- if (translate && gai_afd->a_af == AF_INET) {\r
- struct in6_addr *in6;\r
-\r
- GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);\r
- in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;\r
- memcpy(&in6->s6_addr32[0], &faith_prefix,\r
- sizeof(struct in6_addr) - sizeof(struct in_addr));\r
- memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));\r
- } else\r
-#endif /* FAITH */\r
- GET_AI(cur->ai_next, gai_afd, ap, port);\r
- if (cur == &sentinel) {\r
- top = cur->ai_next;\r
- GET_CANONNAME(top, hp->h_name);\r
- }\r
- cur = cur->ai_next;\r
- }\r
-#ifdef ENABLE_IPV6\r
- freehostent(hp);\r
-#endif\r
- *res = top;\r
- return SUCCESS;\r
- free:\r
- if (top)\r
- freeaddrinfo(top);\r
-#ifdef ENABLE_IPV6\r
- if (hp)\r
- freehostent(hp);\r
-#endif\r
-/* bad: */\r
- *res = NULL;\r
- return error;\r
-}\r