#include <netdb.h>
#include <netdb_async.h>
#include <pthread.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <netinfo/_lu_types.h>
#include <netinfo/lookup.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <libkern/OSByteOrder.h>
#include "lu_host.h"
#include "lu_utils.h"
extern mach_port_t _lu_port;
extern int _lu_running(void);
extern int h_errno;
#define msgh_request_port msgh_remote_port
#define msgh_reply_port msgh_local_port
typedef union
{
gethostbyaddr_async_callback hostAddr;
gethostbyname_async_callback hostName;
getipnodebyaddr_async_callback nodeAddr;
getipnodebyname_async_callback nodeName;
} a_request_callout_t;
typedef struct a_requests
{
struct a_requests *next;
int retry;
struct
{
int proc;
ooline_data data;
unsigned int dataLen;
int want;
} request;
mach_port_t replyPort;
a_request_callout_t callout;
void *context;
struct hostent *hent;
} a_requests_t;
static a_requests_t *a_requests = NULL;
static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
#define MAX_LOOKUP_ATTEMPTS 10
static kern_return_t
_lookup_all_tx(mach_port_t server, int proc, ooline_data indata, mach_msg_type_number_t indataCnt, mach_port_t *replyPort)
{
typedef struct
{
mach_msg_header_t Head;
NDR_record_t NDR;
int proc;
mach_msg_type_number_t indataCnt;
unit indata[4096];
} Request;
Request In;
register Request *InP = &In;
mach_msg_return_t mr;
unsigned int msgh_size;
if (indataCnt > 4096) return MIG_ARRAY_TOO_LARGE;
if (*replyPort == MACH_PORT_NULL)
{
mr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, replyPort);
if (mr != KERN_SUCCESS) return mr;
}
msgh_size = (sizeof(Request) - 16384) + ((4 * indataCnt));
InP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
InP->Head.msgh_request_port = server;
InP->Head.msgh_reply_port = *replyPort;
InP->Head.msgh_id = 4241776;
InP->NDR = NDR_record;
InP->proc = proc;
InP->indataCnt = indataCnt;
memcpy((char *)InP->indata, (const char *)indata, 4 * indataCnt);
mr = mach_msg(&InP->Head,
MACH_SEND_MSG,
msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
switch (mr)
{
case MACH_MSG_SUCCESS:
mr = KERN_SUCCESS;
break;
case MACH_SEND_INVALID_REPLY :
(void)mach_port_mod_refs(mach_task_self(), *replyPort, MACH_PORT_RIGHT_RECEIVE, -1);
*replyPort = MACH_PORT_NULL;
break;
default:
break;
}
return mr;
}
static kern_return_t
_lookup_all_rx(void *msg, ooline_data *outdata, mach_msg_type_number_t *outdataCnt, security_token_t *token)
{
typedef struct
{
mach_msg_header_t Head;
mach_msg_body_t msgh_body;
mach_msg_ool_descriptor_t outdata;
NDR_record_t NDR;
mach_msg_type_number_t outdataCnt;
mach_msg_format_0_trailer_t trailer;
} Reply;
register Reply *OutP = msg;
mach_msg_format_0_trailer_t *TrailerP;
boolean_t msgh_simple;
if (OutP->Head.msgh_id != (4241776 + 100))
{
if (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) return MIG_SERVER_DIED;
else return MIG_REPLY_MISMATCH;
}
msgh_simple = !(OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);
TrailerP = (mach_msg_format_0_trailer_t *)((vm_offset_t)OutP + round_msg(OutP->Head.msgh_size));
if (TrailerP->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0) return MIG_TRAILER_ERROR;
if (OutP->NDR.int_rep != NDR_record.int_rep)
{
if (msgh_simple)
{
((mig_reply_error_t *)OutP)->RetCode = OSReadSwapInt32(&(((mig_reply_error_t *)OutP)->RetCode), 0);
}
else
{
OutP->outdataCnt = OSReadSwapInt32(&(OutP->outdataCnt), 0);
}
}
if (msgh_simple && ((mig_reply_error_t *)OutP)->RetCode != KERN_SUCCESS) return ((mig_reply_error_t *)OutP)->RetCode;
*outdata = (ooline_data)(OutP->outdata.address);
*outdataCnt = OutP->outdataCnt;
*token = TrailerP->msgh_sender;
return KERN_SUCCESS;
}
static a_requests_t *
request_extract(mach_port_t port)
{
a_requests_t *request0, *request;
pthread_mutex_lock(&a_requests_lock);
request0 = NULL;
request = a_requests;
while (request != NULL)
{
if (port == request->replyPort)
{
if (request0 != NULL)
{
request0->next = request->next;
}
else
{
a_requests = request->next;
}
break;
}
else
{
request0 = request;
request = request->next;
}
}
pthread_mutex_unlock(&a_requests_lock);
return request;
}
static void
request_queue(a_requests_t *request)
{
pthread_mutex_lock(&a_requests_lock);
request->next = a_requests;
a_requests = request;
pthread_mutex_unlock(&a_requests_lock);
return;
}
static boolean_t
sendCannedReply(a_requests_t *request, int *error)
{
mig_reply_error_t Out;
register mig_reply_error_t *OutP = &Out;
kern_return_t kr;
mach_msg_return_t mr;
unsigned int msgh_size;
mach_port_t sendPort;
mach_msg_type_name_t sendType;
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &request->replyPort);
if (kr != KERN_SUCCESS)
{
*error = NO_RECOVERY;
return FALSE;
}
kr = mach_port_extract_right(mach_task_self(), request->replyPort, MACH_MSG_TYPE_MAKE_SEND_ONCE, &sendPort, &sendType);
if (kr != KERN_SUCCESS)
{
(void)mach_port_destroy(mach_task_self(), request->replyPort);
request->replyPort = MACH_PORT_NULL;
*error = NO_RECOVERY;
return FALSE;
}
msgh_size = sizeof(Out);
OutP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
OutP->Head.msgh_request_port = sendPort;
OutP->Head.msgh_reply_port = MACH_PORT_NULL;
OutP->Head.msgh_id = 4241776 + 100;
OutP->RetCode = MIG_REMOTE_ERROR;
OutP->NDR = NDR_record;
mr = mach_msg(&OutP->Head, MACH_SEND_MSG, msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (mr != MACH_MSG_SUCCESS)
{
if (mr == MACH_SEND_INVALID_REPLY)
{
(void)mach_port_destroy(mach_task_self(), request->replyPort);
request->replyPort = MACH_PORT_NULL;
}
*error = NO_RECOVERY;
return FALSE;
}
return TRUE;
}
static void
_async_cancel(mach_port_t port)
{
a_requests_t *request;
request = request_extract(port);
if (request)
{
(void)mach_port_mod_refs(mach_task_self(), request->replyPort, MACH_PORT_RIGHT_RECEIVE, -1);
if (request->request.data) free(request->request.data);
if (request->hent) freehostent(request->hent);
free(request);
}
return;
}
static mach_port_t
_gethostbyaddr_async_start(const char *addr, int len, int type, a_request_callout_t callout, void *context, int *error)
{
void *address;
int proc;
a_requests_t *request;
int want;
static int proc4 = -1;
struct in_addr *v4addr;
static int proc6 = -1;
struct in6_addr *v6addr;
want = WANT_A4_ONLY;
if (type == AF_INET6) want = WANT_A6_ONLY;
if ((type == AF_INET6) && (len == 16) && (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr)))
{
addr += 12;
len = 4;
type = AF_INET;
want = WANT_MAPPED_A4_ONLY;
}
switch (type)
{
case AF_INET:
{
if (proc4 < 0)
{
if (_lookup_link(_lu_port, "gethostbyaddr", &proc4) != KERN_SUCCESS)
{
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
}
if (len != sizeof(struct in_addr))
{
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
v4addr = malloc(len);
memmove(v4addr, addr, len);
v4addr->s_addr = htonl(v4addr->s_addr);
address = (void *)v4addr;
proc = proc4;
break;
}
case AF_INET6:
{
if (proc6 < 0)
{
if (_lookup_link(_lu_port, "getipv6nodebyaddr", &proc6) != KERN_SUCCESS)
{
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
}
if (len != sizeof(struct in6_addr))
{
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
v6addr = malloc(len);
memmove(v6addr, addr, len);
v6addr->__u6_addr.__u6_addr32[0] = htonl(v6addr->__u6_addr.__u6_addr32[0]);
v6addr->__u6_addr.__u6_addr32[1] = htonl(v6addr->__u6_addr.__u6_addr32[1]);
v6addr->__u6_addr.__u6_addr32[2] = htonl(v6addr->__u6_addr.__u6_addr32[2]);
v6addr->__u6_addr.__u6_addr32[3] = htonl(v6addr->__u6_addr.__u6_addr32[3]);
address = (void *)v6addr;
proc = proc6;
break;
}
default:
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
request = malloc(sizeof(a_requests_t));
request->next = NULL;
request->retry = MAX_LOOKUP_ATTEMPTS;
request->request.proc = proc;
request->request.data = (ooline_data)address;
request->request.dataLen = len / BYTES_PER_XDR_UNIT;
request->request.want = want;
request->replyPort = MACH_PORT_NULL;
request->callout = callout;
request->context = context;
request->hent = NULL;
if (_lookup_all_tx(_lu_port, request->request.proc, request->request.data, request->request.dataLen, &request->replyPort) == KERN_SUCCESS)
{
request_queue(request);
}
else
{
if (request->request.data) free(request->request.data);
free(request);
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
return request->replyPort;
}
static boolean_t
_gethostbyaddr_async_handleReply(void *replyMsg, a_requests_t **requestP, struct hostent **he, int *error)
{
int count;
ooline_data data;
unsigned int datalen;
XDR inxdr;
mach_msg_header_t *msg = (mach_msg_header_t *)replyMsg;
a_requests_t *request;
kern_return_t status;
security_token_t token;
request = request_extract(msg->msgh_local_port);
if (!request)
{
return FALSE;
}
*requestP = request;
*he = NULL;
*error = 0;
status = _lookup_all_rx(replyMsg, &data, &datalen, &token);
switch (status)
{
case KERN_SUCCESS:
break;
case MIG_SERVER_DIED:
if (--request->retry > 0)
{
if (_lookup_all_tx(_lu_port, request->request.proc, request->request.data, request->request.dataLen, &request->replyPort) == KERN_SUCCESS)
{
request_queue(request);
return FALSE;
}
}
default:
*error = HOST_NOT_FOUND;
return TRUE;
}
datalen *= BYTES_PER_XDR_UNIT;
if (token.val[0] != 0)
{
vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
*error = NO_RECOVERY;
return TRUE;
}
xdrmem_create(&inxdr, data, datalen, XDR_DECODE);
count = 0;
if (!xdr_int(&inxdr, &count))
{
xdr_destroy(&inxdr);
vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
*error = NO_RECOVERY;
return TRUE;
}
if (count == 0)
{
xdr_destroy(&inxdr);
vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
*error = HOST_NOT_FOUND;
*he = NULL;
return TRUE;
}
*he = extract_host(&inxdr, request->request.want, error);
xdr_destroy(&inxdr);
vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
return TRUE;
}
mach_port_t
gethostbyaddr_async_start(const char *addr, int len, int type, gethostbyaddr_async_callback callout, void *context)
{
a_request_callout_t cb;
mach_port_t mp;
if (!_lu_running())
{
h_errno = NO_RECOVERY;
return MACH_PORT_NULL;
}
cb.hostAddr = callout;
mp = _gethostbyaddr_async_start(addr, len, type, cb, context, &h_errno);
return mp;
}
void
gethostbyaddr_async_cancel(mach_port_t port)
{
_async_cancel(port);
return;
}
void
gethostbyaddr_async_handleReply(void *replyMsg)
{
int error = 0;
struct hostent *he = NULL;
a_requests_t *request = NULL;
if (_gethostbyaddr_async_handleReply(replyMsg, &request, &he, &error))
{
h_errno = error;
(request->callout.hostAddr)(he, request->context);
(void)mach_port_mod_refs(mach_task_self(), request->replyPort, MACH_PORT_RIGHT_RECEIVE, -1);
if (request->request.data) free(request->request.data);
free(request);
if (he != NULL) freehostent(he);
}
return;
}
mach_port_t
getipnodebyaddr_async_start(const void *addr, size_t len, int af, int *error, getipnodebyaddr_async_callback callout, void *context)
{
a_request_callout_t cb;
mach_port_t mp;
if (!_lu_running())
{
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
cb.nodeAddr = callout;
mp = _gethostbyaddr_async_start(addr, len, af, cb, context, error);
return mp;
}
void
getipnodebyaddr_async_cancel(mach_port_t port)
{
_async_cancel(port);
return;
}
void
getipnodebyaddr_async_handleReply(void *replyMsg)
{
int error = 0;
struct hostent *he = NULL;
a_requests_t *request = NULL;
if (_gethostbyaddr_async_handleReply(replyMsg, &request, &he, &error))
{
(request->callout.nodeAddr)(he, error, request->context);
(void)mach_port_mod_refs(mach_task_self(), request->replyPort, MACH_PORT_RIGHT_RECEIVE, -1);
if (request->request.data) free(request->request.data);
free(request);
}
return;
}
static mach_port_t
_gethostbyname_async_start(const char *name, int want, int *error, a_request_callout_t callout, void *context)
{
int af;
boolean_t is_addr = FALSE;
mach_port_t mp = MACH_PORT_NULL;
XDR outxdr;
static int proc;
a_requests_t *request;
static int proc4 = -1;
static int proc6 = -1;
struct in_addr v4addr;
struct in6_addr v6addr;
if ((name == NULL) || (name[0] == '\0'))
{
*error = NO_DATA;
return MACH_PORT_NULL;
}
af = (want == WANT_A4_ONLY) ? AF_INET: AF_INET6;
if ((af == AF_INET) || (want == WANT_MAPPED_A4_ONLY))
{
if (proc4 < 0)
{
if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS)
{
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
}
proc = proc4;
}
else
{
if (proc6 < 0)
{
if (_lookup_link(_lu_port, "getipv6nodebyname", &proc6) != KERN_SUCCESS)
{
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
}
proc = proc6;
}
request = malloc(sizeof(a_requests_t));
request->next = NULL;
request->retry = MAX_LOOKUP_ATTEMPTS;
request->request.proc = proc;
request->request.data = NULL;
request->request.dataLen = 0;
request->request.want = want;
request->replyPort = MACH_PORT_NULL;
request->callout = callout;
request->context = context;
request->hent = NULL;
switch (af)
{
case AF_INET:
{
memset(&v4addr, 0, sizeof(struct in_addr));
if (inet_aton(name, &v4addr) == 1)
{
request->hent = fake_hostent(name, v4addr);
is_addr = TRUE;
}
break;
}
case AF_INET6:
{
memset(&v6addr, 0, sizeof(struct in6_addr));
if (inet_pton(af, name, &v6addr) == 1)
{
request->hent = fake_hostent6(name, v6addr);
is_addr = TRUE;
break;
}
memset(&v4addr, 0, sizeof(struct in_addr));
if (inet_aton(name, &v4addr) == 1)
{
if (want == WANT_A4_ONLY)
{
free(request);
*error = HOST_NOT_FOUND;
return MACH_PORT_NULL;
}
v6addr.__u6_addr.__u6_addr32[0] = 0x00000000;
v6addr.__u6_addr.__u6_addr32[1] = 0x00000000;
v6addr.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
memmove(&(v6addr.__u6_addr.__u6_addr32[3]), &(v4addr.s_addr), sizeof(struct in_addr));
request->hent = fake_hostent6(name, v6addr);
is_addr = TRUE;
}
break;
}
default:
free(request);
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
if (is_addr)
{
if (sendCannedReply(request, error))
{
request_queue(request);
return request->replyPort;
}
else
{
freehostent(request->hent);
free(request);
return MACH_PORT_NULL;
}
}
request->request.dataLen = _LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT;
request->request.data = malloc(request->request.dataLen);
xdrmem_create(&outxdr, request->request.data, request->request.dataLen, XDR_ENCODE);
if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
{
xdr_destroy(&outxdr);
free(request->request.data);
free(request);
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
request->request.dataLen = xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT;
if (_lookup_all_tx(_lu_port, request->request.proc, request->request.data, request->request.dataLen, &request->replyPort) == KERN_SUCCESS)
{
request_queue(request);
mp = request->replyPort;
}
else
{
free(request->request.data);
free(request);
*error = NO_RECOVERY;
mp = MACH_PORT_NULL;
}
xdr_destroy(&outxdr);
return mp;
}
static boolean_t
_gethostbyname_async_handleReply(void *replyMsg, a_requests_t **requestP, struct hostent **he, int *error)
{
int count;
unsigned int datalen;
XDR inxdr;
ooline_data data;
mach_msg_header_t *msg = (mach_msg_header_t *)replyMsg;
a_requests_t *request;
kern_return_t status;
security_token_t token;
int want;
request = request_extract(msg->msgh_local_port);
if (!request)
{
return FALSE;
}
*requestP = request;
*he = NULL;
*error = 0;
if (request->hent)
{
*he = request->hent;
return TRUE;
}
status = _lookup_all_rx(replyMsg, &data, &datalen, &token);
switch (status)
{
case KERN_SUCCESS:
break;
case MIG_SERVER_DIED:
if (--request->retry > 0)
{
if (_lookup_all_tx(_lu_port, request->request.proc, request->request.data, request->request.dataLen, &request->replyPort) == KERN_SUCCESS)
{
request_queue(request);
return FALSE;
}
}
default:
*error = HOST_NOT_FOUND;
return TRUE;
}
datalen *= BYTES_PER_XDR_UNIT;
if (token.val[0] != 0)
{
vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
*error = NO_RECOVERY;
return TRUE;
}
xdrmem_create(&inxdr, data, datalen, XDR_DECODE);
count = 0;
if (!xdr_int(&inxdr, &count))
{
xdr_destroy(&inxdr);
vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
*error = NO_RECOVERY;
return TRUE;
}
if (count == 0)
{
xdr_destroy(&inxdr);
vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
*error = HOST_NOT_FOUND;
return TRUE;
}
want = request->request.want;
if (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) want = WANT_A6_ONLY;
*he = extract_host(&inxdr, want, error);
xdr_destroy(&inxdr);
vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
return TRUE;
}
mach_port_t
gethostbyname_async_start(const char *name, gethostbyname_async_callback callout, void *context)
{
a_request_callout_t cb;
int error;
mach_port_t mp = MACH_PORT_NULL;
if (!_lu_running())
{
h_errno = NO_RECOVERY;
return MACH_PORT_NULL;
}
cb.hostName = callout;
mp = _gethostbyname_async_start(name, WANT_A4_ONLY, &error, cb, context);
if (mp == MACH_PORT_NULL)
{
h_errno = error;
}
return mp;
}
void
gethostbyname_async_cancel(mach_port_t port)
{
_async_cancel(port);
return;
}
void
gethostbyname_async_handleReply(void *replyMsg)
{
int error;
struct hostent *he;
a_requests_t *request;
if (_gethostbyname_async_handleReply(replyMsg, &request, &he, &error))
{
h_errno = error;
(request->callout.hostAddr)(he, request->context);
(void)mach_port_mod_refs(mach_task_self(), request->replyPort, MACH_PORT_RIGHT_RECEIVE, -1);
if (request->request.data) free(request->request.data);
free(request);
if (he != NULL) freehostent(he);
}
return;
}
mach_port_t
getipnodebyname_async_start(const char *name, int af, int flags, int *error, getipnodebyname_async_callback callout, void *context)
{
a_request_callout_t cb;
int if4 = 0;
int if6 = 0;
mach_port_t mp = MACH_PORT_NULL;
int want = WANT_A4_ONLY;
struct ifaddrs *ifa, *ifap;
if (!_lu_running())
{
h_errno = NO_RECOVERY;
return MACH_PORT_NULL;
}
if (flags & AI_ADDRCONFIG)
{
if (getifaddrs(&ifa) < 0)
{
*error = NO_RECOVERY;
return MACH_PORT_NULL;
}
for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
{
if (ifap->ifa_addr == NULL) continue;
if ((ifap->ifa_flags & IFF_UP) == 0) continue;
if (ifap->ifa_addr->sa_family == AF_INET)
{
if4++;
}
else if (ifap->ifa_addr->sa_family == AF_INET6)
{
if6++;
}
}
freeifaddrs(ifa);
if ((if4 == 0) && (if6 == 0))
{
*error = NO_ADDRESS;
return MACH_PORT_NULL;
}
}
switch (af)
{
case AF_INET:
{
want = WANT_A4_ONLY;
if ((flags & AI_ADDRCONFIG) && (if4 == 0))
{
*error = NO_ADDRESS;
return MACH_PORT_NULL;
}
}
break;
case AF_INET6:
{
want = WANT_A6_ONLY;
if (flags & (AI_V4MAPPED|AI_V4MAPPED_CFG))
{
if (flags & AI_ALL)
{
want = WANT_A6_PLUS_MAPPED_A4;
}
else
{
want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
}
}
else
{
if ((flags & AI_ADDRCONFIG) && (if6 == 0))
{
*error = NO_ADDRESS;
return MACH_PORT_NULL;
}
}
}
break;
}
cb.nodeName = callout;
mp = _gethostbyname_async_start(name, want, &h_errno, cb, context);
return mp;
}
void
getipnodebyname_async_cancel(mach_port_t port)
{
_async_cancel(port);
return;
}
void
getipnodebyname_async_handleReply(void *replyMsg)
{
int error = 0;
struct hostent *he = NULL;
a_requests_t *request = NULL;
static int proc4 = -1;
if (_gethostbyname_async_handleReply(replyMsg, &request, &he, &error))
{
if ((he == NULL) && (error == HOST_NOT_FOUND) && ((request->request.want == WANT_A6_PLUS_MAPPED_A4) || (request->request.want == WANT_A6_OR_MAPPED_A4_IF_NO_A6)))
{
if (proc4 < 0)
{
if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS)
{
error = NO_RECOVERY;
goto answer;
}
}
request->request.proc = proc4;
request->request.want = WANT_MAPPED_A4_ONLY;
if (_lookup_all_tx(_lu_port, request->request.proc, request->request.data, request->request.dataLen, &request->replyPort) == KERN_SUCCESS)
{
request_queue(request);
return;
}
else
{
error = NO_RECOVERY;
}
}
answer:
(request->callout.nodeName)(he, error, request->context);
(void)mach_port_mod_refs(mach_task_self(), request->replyPort, MACH_PORT_RIGHT_RECEIVE, -1);
if (request->request.data != NULL) free(request->request.data);
free(request);
}
return;
}