1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2006,2008 Oracle. All rights reserved. 5 * 6 * $Id: os_addrinfo.c,v 1.11 2008/01/08 20:58:43 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#define __INCLUDE_NETWORKING 1 12#include "db_int.h" 13 14/* 15 * __os_getaddrinfo and __os_freeaddrinfo wrap the getaddrinfo and freeaddrinfo 16 * calls, as well as the associated platform dependent error handling, mapping 17 * the error return to a ANSI C/POSIX error return. 18 */ 19 20/* 21 * __os_getaddrinfo -- 22 * 23 * PUBLIC: #if defined(HAVE_REPLICATION_THREADS) 24 * PUBLIC: int __os_getaddrinfo __P((ENV *, const char *, u_int, 25 * PUBLIC: const char *, const ADDRINFO *, ADDRINFO **)); 26 * PUBLIC: #endif 27 */ 28int 29__os_getaddrinfo(env, nodename, port, servname, hints, res) 30 ENV *env; 31 const char *nodename, *servname; 32 u_int port; 33 const ADDRINFO *hints; 34 ADDRINFO **res; 35{ 36#ifdef HAVE_GETADDRINFO 37 int ret; 38 39 if ((ret = getaddrinfo(nodename, servname, hints, res)) == 0) 40 return (0); 41 42 __db_errx(env, "%s(%u): host lookup failed: %s", 43 nodename == NULL ? "" : nodename, port, 44#ifdef DB_WIN32 45 gai_strerrorA(ret)); 46#else 47 gai_strerror(ret)); 48#endif 49 return (__os_posix_err(ret)); 50#else 51 ADDRINFO *answer; 52 struct hostent *hostaddr; 53 struct sockaddr_in sin; 54 u_int32_t tmpaddr; 55 int ret; 56 57 COMPQUIET(hints, NULL); 58 COMPQUIET(servname, NULL); 59 60 /* INADDR_NONE is not defined on Solaris 2.6, 2.7 or 2.8. */ 61#ifndef INADDR_NONE 62#define INADDR_NONE ((u_long)0xffffffff) 63#endif 64 65 /* 66 * Basic implementation of IPv4 component of getaddrinfo. 67 * Limited to the functionality used by repmgr. 68 */ 69 memset(&sin, 0, sizeof(sin)); 70 sin.sin_family = AF_INET; 71 if (nodename) { 72 if (nodename[0] == '\0') 73 sin.sin_addr.s_addr = htonl(INADDR_ANY); 74 else if ((tmpaddr = inet_addr(nodename)) != INADDR_NONE) { 75 sin.sin_addr.s_addr = tmpaddr; 76 } else { 77 hostaddr = gethostbyname(nodename); 78 if (hostaddr == NULL) { 79#ifdef DB_WIN32 80 ret = __os_get_neterr(); 81 __db_syserr(env, ret, 82 "%s(%u): host lookup failed", 83 nodename == NULL ? "" : nodename, port); 84 return (__os_posix_err(ret)); 85#else 86 /* 87 * Historic UNIX systems used the h_errno 88 * global variable to return gethostbyname 89 * errors. The only function we currently 90 * use that needs h_errno is gethostbyname, 91 * so we deal with it here. 92 * 93 * hstrerror is not available on Solaris 2.6 94 * (it is in libresolv but is a private, 95 * unexported symbol). 96 */ 97#ifdef HAVE_HSTRERROR 98 __db_errx(env, 99 "%s(%u): host lookup failed: %s", 100 nodename == NULL ? "" : nodename, port, 101 hstrerror(h_errno)); 102#else 103 __db_errx(env, 104 "%s(%u): host lookup failed: %d", 105 nodename == NULL ? "" : nodename, port, 106 h_errno); 107#endif 108 switch (h_errno) { 109 case HOST_NOT_FOUND: 110 case NO_DATA: 111 return (EHOSTUNREACH); 112 case TRY_AGAIN: 113 return (EAGAIN); 114 case NO_RECOVERY: 115 default: 116 return (EFAULT); 117 } 118 /* NOTREACHED */ 119#endif 120 } 121 memcpy(&(sin.sin_addr), 122 hostaddr->h_addr, (size_t)hostaddr->h_length); 123 } 124 } else /* No host specified. */ 125 sin.sin_addr.s_addr = htonl(INADDR_ANY); 126 sin.sin_port = htons((u_int16_t)port); 127 128 if ((ret = __os_calloc(env, 1, sizeof(ADDRINFO), &answer)) != 0) 129 return (ret); 130 if ((ret = __os_malloc(env, sizeof(sin), &answer->ai_addr)) != 0) { 131 __os_free(env, answer); 132 return (ret); 133 } 134 135 answer->ai_family = AF_INET; 136 answer->ai_protocol = IPPROTO_TCP; 137 answer->ai_socktype = SOCK_STREAM; 138 answer->ai_addrlen = sizeof(sin); 139 memcpy(answer->ai_addr, &sin, sizeof(sin)); 140 *res = answer; 141 142 return (0); 143#endif /* HAVE_GETADDRINFO */ 144} 145 146/* 147 * __os_freeaddrinfo -- 148 * 149 * PUBLIC: #if defined(HAVE_REPLICATION_THREADS) 150 * PUBLIC: void __os_freeaddrinfo __P((ENV *, ADDRINFO *)); 151 * PUBLIC: #endif 152 */ 153void 154__os_freeaddrinfo(env, ai) 155 ENV *env; 156 ADDRINFO *ai; 157{ 158#ifdef HAVE_GETADDRINFO 159 COMPQUIET(env, NULL); 160 161 freeaddrinfo(ai); 162#else 163 ADDRINFO *next, *tmpaddr; 164 165 for (next = ai; next != NULL; next = tmpaddr) { 166 if (next->ai_canonname != NULL) 167 __os_free(env, next->ai_canonname); 168 169 if (next->ai_addr != NULL) 170 __os_free(env, next->ai_addr); 171 172 tmpaddr = next->ai_next; 173 __os_free(env, next); 174 } 175#endif 176} 177