X-Git-Url: https://git.saurik.com/apple/libinfo.git/blobdiff_plain/e6b95798e71dad1fb3669ea0b8963d24ddd65f93..b3dd680f589a1f02e301659e04768ef61be3b843:/lookup.subproj/lu_host_async.c diff --git a/lookup.subproj/lu_host_async.c b/lookup.subproj/lu_host_async.c index 6b50471..14a0eca 100644 --- a/lookup.subproj/lu_host_async.c +++ b/lookup.subproj/lu_host_async.c @@ -23,946 +23,333 @@ */ #include -/* async gethostbyXXX function prototypes */ #include #include #include #include -#include -#include -#include -#include #include #include #include #include #include -#include +#include #include "lu_host.h" #include "lu_utils.h" -extern mach_port_t _lu_port; -extern int _lu_running(void); +#define IPV6_ADDR_LEN 16 +#define IPV4_ADDR_LEN 4 -extern int h_errno; - -#define msgh_request_port msgh_remote_port -#define msgh_reply_port msgh_local_port - - -typedef union +typedef struct { - 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; /* if reply known in XXX_start() */ -} 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 + void *user_context; + int want; +} my_context_t; -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) +mach_port_t +gethostbyaddr_async_start(const char *addr, int len, int family, gethostbyaddr_async_callback callback, void *context) { - 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_size = msgh_size; /* msgh_size passed as argument */ - 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, /* msg */ - MACH_SEND_MSG, /* options */ - msgh_size, /* send_size */ - 0, /* rcv_size */ - MACH_PORT_NULL, /* rcv_name */ - MACH_MSG_TIMEOUT_NONE, /* timeout */ - MACH_PORT_NULL); /* notify */ - - 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 int proc = 1; + int32_t want, status; + kvbuf_t *request; + mach_port_t mp; + my_context_t *my_context; -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; + mp = MACH_PORT_NULL; - /* - * typedef struct { - * mach_msg_header_t Head; - * NDR_record_t NDR; - * kern_return_t RetCode; - * } mig_reply_error_t; - */ + if (addr == NULL) return MACH_PORT_NULL; + if (len == 0) return MACH_PORT_NULL; + if ((family != AF_INET) && (family != AF_INET6)) return MACH_PORT_NULL; - register Reply *OutP = msg; - mach_msg_format_0_trailer_t *TrailerP; - boolean_t msgh_simple; + want = WANT_A4_ONLY; + if (family == AF_INET6) want = WANT_A6_ONLY; - if (OutP->Head.msgh_id != (4241776 + 100)) + if ((family == AF_INET6) && (len == IPV6_ADDR_LEN) && (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr))) { - if (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) return MIG_SERVER_DIED; - else return MIG_REPLY_MISMATCH; + addr += 12; + len = 4; + family = AF_INET; + want = WANT_MAPPED_A4_ONLY; } - 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 (proc < 0) { - if (msgh_simple) - { - ((mig_reply_error_t *)OutP)->RetCode = OSReadSwapInt32(&(((mig_reply_error_t *)OutP)->RetCode), 0); - } - else - { - OutP->outdataCnt = OSReadSwapInt32(&(OutP->outdataCnt), 0); - } + status = LI_DSLookupGetProcedureNumber("gethostbyaddr", &proc); + if (status != KERN_SUCCESS) return MACH_PORT_NULL; } - 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; -} + request = kvbuf_query("ksku", "address", addr, "family", want); + if (request == NULL) return MACH_PORT_NULL; -static a_requests_t * -request_extract(mach_port_t port) -{ - a_requests_t *request0, *request; + my_context = (my_context_t *)calloc(1, sizeof(my_context_t)); + if (my_context == NULL) return MACH_PORT_NULL; - pthread_mutex_lock(&a_requests_lock); + my_context->user_context = context; + my_context->want = want; - request0 = NULL; - request = a_requests; + status = LI_async_start(&mp, proc, request, (void *)callback, my_context); - while (request != NULL) - { - if (port == request->replyPort) - { - /* request found, remove from list */ - if (request0 != NULL) - { - request0->next = request->next; - } - else - { - a_requests = request->next; - } - - break; - } - else - { - /* not this request, skip to next */ - request0 = request; - request = request->next; - } - } - - pthread_mutex_unlock(&a_requests_lock); - - return request; + kvbuf_free(request); + return mp; } -static void -request_queue(a_requests_t *request) +void +gethostbyaddr_async_cancel(mach_port_t port) { - pthread_mutex_lock(&a_requests_lock); + my_context_t *my_context; - request->next = a_requests; - a_requests = request; + my_context = NULL; - pthread_mutex_unlock(&a_requests_lock); + LI_async_call_cancel(port, (void **)&my_context); - return; + if (my_context != NULL) free(my_context); } -static boolean_t -sendCannedReply(a_requests_t *request, int *error) +void +gethostbyaddr_async_handleReply(void *msg) { - /* - * typedef struct { - * mach_msg_header_t Head; - * NDR_record_t NDR; - * kern_return_t RetCode; - * } mig_reply_error_t; - */ - - 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; + gethostbyaddr_async_callback callback; + struct hostent *out; + uint32_t len, want; + int status; + kvarray_t *reply; + my_context_t *my_context; + void *context; - mach_port_t sendPort; - mach_msg_type_name_t sendType; + callback = (gethostbyaddr_async_callback)NULL; + my_context = NULL; + context = NULL; + len = 0; + reply = NULL; - /* - * allocate reply port - */ - kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &request->replyPort); - if (kr != KERN_SUCCESS) + status = LI_async_handle_reply(msg, &reply, (void **)&callback, (void **)&my_context); + if ((status != KERN_SUCCESS) || (reply == NULL)) { - *error = NO_RECOVERY; - return FALSE; + if (status == MIG_REPLY_MISMATCH) return; + if (callback != NULL) + { + if (my_context != NULL) context = my_context->user_context; + callback(NULL, context); + free(my_context); + return; + } } - kr = mach_port_extract_right(mach_task_self(), request->replyPort, MACH_MSG_TYPE_MAKE_SEND_ONCE, &sendPort, &sendType); - if (kr != KERN_SUCCESS) + want = WANT_A4_ONLY; + if (my_context != NULL) { - (void)mach_port_destroy(mach_task_self(), request->replyPort); - request->replyPort = MACH_PORT_NULL; - *error = NO_RECOVERY; - return FALSE; + context = my_context->user_context; + want = my_context->want; + free(my_context); } - /* - * queue reply message - */ - msgh_size = sizeof(Out); - OutP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0); -// OutP->Head.msgh_size = msgh_size; /* msgh_size passed as argument */ - 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; - } + out = extract_host(reply, want); + kvarray_free(reply); - return TRUE; + callback(out, context); } -static void -_async_cancel(mach_port_t port) +mach_port_t +getipnodebyaddr_async_start(const void *addr, size_t len, int family, int *error, getipnodebyaddr_async_callback callback, void *context) { - 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); - } + static int proc = 1; + int32_t want, status; + kvbuf_t *request; + mach_port_t mp; + my_context_t *my_context; - return; -} + mp = MACH_PORT_NULL; -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; + if (addr == NULL) return MACH_PORT_NULL; + if (len == 0) return MACH_PORT_NULL; + if ((family != AF_INET) && (family != AF_INET6)) return MACH_PORT_NULL; want = WANT_A4_ONLY; - if (type == AF_INET6) want = WANT_A6_ONLY; + if (family == AF_INET6) want = WANT_A6_ONLY; - if ((type == AF_INET6) && (len == 16) && (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr))) + if ((family == AF_INET6) && (len == IPV6_ADDR_LEN) && (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr))) { addr += 12; len = 4; - type = AF_INET; + family = AF_INET; want = WANT_MAPPED_A4_ONLY; } - switch (type) + if (proc < 0) { - 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); - - 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; + status = LI_DSLookupGetProcedureNumber("gethostbyaddr", &proc); + if (status != KERN_SUCCESS) 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; - - /* - * allocate reply port, send query to lookupd - */ - 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; - } + request = kvbuf_query("ksku", "address", addr, "family", want); + if (request == NULL) return MACH_PORT_NULL; - return request->replyPort; -} + my_context = (my_context_t *)calloc(1, sizeof(my_context_t)); + if (my_context == NULL) return MACH_PORT_NULL; -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) - { - /* excuse me, what happenned to the request info? */ - return FALSE; - } + my_context->user_context = context; + my_context->want = want; - *requestP = request; - *he = NULL; - *error = 0; + status = LI_async_start(&mp, proc, request, (void *)callback, my_context); - /* unpack the reply */ - status = _lookup_all_rx(replyMsg, &data, &datalen, &token); - switch (status) - { - case KERN_SUCCESS: - break; - - case MIG_SERVER_DIED: - if (--request->retry > 0) - { - /* retry the request */ - if (_lookup_all_tx(_lu_port, request->request.proc, request->request.data, request->request.dataLen, &request->replyPort) == KERN_SUCCESS) - { - request_queue(request); - return FALSE; - } - } - /* fall through */ - - 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)) - { - /* if we have an answer to provide */ - 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); + kvbuf_free(request); return mp; } void getipnodebyaddr_async_cancel(mach_port_t port) { - _async_cancel(port); - return; -} + my_context_t *my_context; -void -getipnodebyaddr_async_handleReply(void *replyMsg) -{ - int error = 0; - struct hostent *he = NULL; - a_requests_t *request = NULL; + my_context = NULL; - if (_gethostbyaddr_async_handleReply(replyMsg, &request, &he, &error)) - { - /* if we have an answer to provide */ - (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); - /* - * Note: it is up to the callback function to call - * freehostent(). - */ - } + LI_async_call_cancel(port, (void **)&my_context); - return; + if (my_context != NULL) free(my_context); } -static mach_port_t -_gethostbyname_async_start(const char *name, int want, int *error, a_request_callout_t callout, void *context) +void +getipnodebyaddr_async_handleReply(void *msg) { - 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 (af == AF_INET6) */ - { - 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) - { - /* return a fake hostent */ - 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) - { - /* return a fake hostent */ - 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)); - - /* return a fake hostent */ - request->hent = fake_hostent6(name, v6addr); - is_addr = TRUE; - } - break; - } + getipnodebyaddr_async_callback callback; + struct hostent *out; + uint32_t len, want; + int status; + kvarray_t *reply; + my_context_t *my_context; + void *context; - default: - free(request); - *error = NO_RECOVERY; - return MACH_PORT_NULL; - } + callback = (getipnodebyaddr_async_callback)NULL; + my_context = NULL; + context = NULL; + len = 0; + reply = NULL; - if (is_addr) + status = LI_async_handle_reply(msg, &reply, (void **)&callback, (void **)&my_context); + if ((status != KERN_SUCCESS) || (reply == NULL)) { - /* - * queue reply message - */ - if (sendCannedReply(request, error)) + if (status == MIG_REPLY_MISMATCH) return; + if (callback != NULL) { - request_queue(request); - return request->replyPort; - } - else - { - freehostent(request->hent); - free(request); - return MACH_PORT_NULL; + if (my_context != NULL) context = my_context->user_context; + callback(NULL, NO_RECOVERY, context); + free(my_context); + return; } } - 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)) + want = WANT_A4_ONLY; + if (my_context != NULL) { - xdr_destroy(&outxdr); - free(request->request.data); - free(request); - *error = NO_RECOVERY; - return MACH_PORT_NULL; + context = my_context->user_context; + want = my_context->want; + free(my_context); } - request->request.dataLen = xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT; + out = extract_host(reply, want); + kvarray_free(reply); - /* - * allocate reply port, send query to lookupd - */ - 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 + if (out == NULL) { - free(request->request.data); - free(request); - *error = NO_RECOVERY; - mp = MACH_PORT_NULL; + callback(NULL, HOST_NOT_FOUND, context); + return; } - xdr_destroy(&outxdr); - return mp; + callback(out, 0, context); } -static boolean_t -_gethostbyname_async_handleReply(void *replyMsg, a_requests_t **requestP, struct hostent **he, int *error) +mach_port_t +gethostbyname_async_start(const char *name, gethostbyname_async_callback callback, void *context) { - 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) - { - /* excuse me, what happenned to the request info? */ - return FALSE; - } - - *requestP = request; - *he = NULL; - *error = 0; - - if (request->hent) - { - /* - * if the reply was already available when the - * request was made - */ - *he = request->hent; - return TRUE; - } - - /* unpack the reply */ - status = _lookup_all_rx(replyMsg, &data, &datalen, &token); - switch (status) - { - case KERN_SUCCESS: - break; - - case MIG_SERVER_DIED: - if (--request->retry > 0) - { - /* - * retry the request - */ - if (_lookup_all_tx(_lu_port, request->request.proc, request->request.data, request->request.dataLen, &request->replyPort) == KERN_SUCCESS) - { - request_queue(request); - return FALSE; - } - } - /* fall through */ - - default: - *error = HOST_NOT_FOUND; - return TRUE; - } - - datalen *= BYTES_PER_XDR_UNIT; + static int proc = 1; + int32_t status; + kvbuf_t *request; + mach_port_t mp; - if (token.val[0] != 0) - { - vm_deallocate(mach_task_self(), (vm_address_t)data, datalen); - *error = NO_RECOVERY; - return TRUE; - } + mp = MACH_PORT_NULL; - xdrmem_create(&inxdr, data, datalen, XDR_DECODE); + if (name == NULL) return MACH_PORT_NULL; - count = 0; - if (!xdr_int(&inxdr, &count)) + if (proc < 0) { - xdr_destroy(&inxdr); - vm_deallocate(mach_task_self(), (vm_address_t)data, datalen); - *error = NO_RECOVERY; - return TRUE; + status = LI_DSLookupGetProcedureNumber("gethostbyname", &proc); + if (status != KERN_SUCCESS) return MACH_PORT_NULL; } - if (count == 0) - { - xdr_destroy(&inxdr); - vm_deallocate(mach_task_self(), (vm_address_t)data, datalen); - *error = HOST_NOT_FOUND; - return TRUE; - } + request = kvbuf_query("ksksks", "name", name, "ipv4", "1", "ipv6", "0"); + if (request == NULL) return MACH_PORT_NULL; - 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; - } + status = LI_async_start(&mp, proc, request, (void *)callback, context); + kvbuf_free(request); return mp; } void gethostbyname_async_cancel(mach_port_t port) { - _async_cancel(port); - return; + LI_async_call_cancel(port, NULL); } void -gethostbyname_async_handleReply(void *replyMsg) +gethostbyname_async_handleReply(void *msg) { - int error; - struct hostent *he; - a_requests_t *request; + gethostbyname_async_callback callback; + struct hostent *out; + uint32_t len; + int status; + kvarray_t *reply; + void *context; + + callback = (gethostbyname_async_callback)NULL; + context = NULL; + len = 0; + reply = NULL; - if (_gethostbyname_async_handleReply(replyMsg, &request, &he, &error)) + status = LI_async_handle_reply(msg, &reply, (void **)&callback, (void **)&context); + if ((status != KERN_SUCCESS) || (reply == NULL)) { - /* if we have an answer to provide */ - 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); + if (status == MIG_REPLY_MISMATCH) return; + if (callback != NULL) + { + callback(NULL, context); + return; + } } - return; + out = extract_host(reply, AF_INET); + kvarray_free(reply); + + callback(out, context); } mach_port_t -getipnodebyname_async_start(const char *name, int af, int flags, int *error, getipnodebyname_async_callback callout, void *context) +getipnodebyname_async_start(const char *name, int family, int flags, int *err, getipnodebyname_async_callback callback, 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; + static int proc = 1; + int32_t status, want, want4, want6, if4, if6; + kvbuf_t *request; + mach_port_t mp; struct ifaddrs *ifa, *ifap; + struct in_addr addr4; + struct in6_addr addr6; + my_context_t *my_context; - if (!_lu_running()) - { - h_errno = NO_RECOVERY; - return MACH_PORT_NULL; - } + if (name == NULL) return MACH_PORT_NULL; + + if (err != NULL) *err = 0; + + if4 = 0; + if6 = 0; + mp = MACH_PORT_NULL; + memset(&addr4, 0, sizeof(struct in_addr)); + memset(&addr6, 0, sizeof(struct in6_addr)); - /* - * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have. - */ if (flags & AI_ADDRCONFIG) { if (getifaddrs(&ifa) < 0) { - *error = NO_RECOVERY; + if (err != NULL) *err = NO_RECOVERY; return MACH_PORT_NULL; } @@ -970,14 +357,8 @@ getipnodebyname_async_start(const char *name, int af, int flags, int *error, get { 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++; - } + if (ifap->ifa_addr->sa_family == AF_INET) if4++; + else if (ifap->ifa_addr->sa_family == AF_INET6) if6++; } freeifaddrs(ifa); @@ -985,7 +366,7 @@ getipnodebyname_async_start(const char *name, int af, int flags, int *error, get /* Bail out if there are no interfaces */ if ((if4 == 0) && (if6 == 0)) { - *error = NO_ADDRESS; + if (err != NULL) *err = NO_RECOVERY; return MACH_PORT_NULL; } } @@ -994,108 +375,133 @@ getipnodebyname_async_start(const char *name, int af, int flags, int *error, get * Figure out what we want. * If user asked for AF_INET, we only want V4 addresses. */ - switch (af) + want = WANT_A4_ONLY; + + if (family == AF_INET) { - case AF_INET: + if ((flags & AI_ADDRCONFIG) && (if4 == 0)) { - want = WANT_A4_ONLY; - if ((flags & AI_ADDRCONFIG) && (if4 == 0)) - { - *error = NO_ADDRESS; - return MACH_PORT_NULL; - } + if (err != NULL) *err = NO_RECOVERY; + return MACH_PORT_NULL; } - break; + } + else + { + /* family == AF_INET6 */ + want = WANT_A6_ONLY; - case AF_INET6: + if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG)) { - want = WANT_A6_ONLY; - if (flags & (AI_V4MAPPED|AI_V4MAPPED_CFG)) + if (flags & AI_ALL) { - if (flags & AI_ALL) - { - want = WANT_A6_PLUS_MAPPED_A4; - } - else - { - want = WANT_A6_OR_MAPPED_A4_IF_NO_A6; - } + want = WANT_A6_PLUS_MAPPED_A4; } else { - if ((flags & AI_ADDRCONFIG) && (if6 == 0)) - { - *error = NO_ADDRESS; - return MACH_PORT_NULL; - } + want = WANT_A6_OR_MAPPED_A4_IF_NO_A6; + } + } + else + { + if ((flags & AI_ADDRCONFIG) && (if6 == 0)) + { + if (err != NULL) *err = NO_RECOVERY; + return MACH_PORT_NULL; } } - break; } - cb.nodeName = callout; - mp = _gethostbyname_async_start(name, want, &h_errno, cb, context); + if (proc < 0) + { + status = LI_DSLookupGetProcedureNumber("gethostbyname", &proc); + if (status != KERN_SUCCESS) return MACH_PORT_NULL; + } + + my_context = (my_context_t *)calloc(1, sizeof(my_context_t)); + if (my_context == NULL) + { + *err = NO_RECOVERY; + return MACH_PORT_NULL; + } + + my_context->user_context = context; + my_context->want = want; + + want4 = 1; + want6 = 1; + + if (want == WANT_A4_ONLY) want6 = 0; + else if (want == WANT_A6_ONLY) want4 = 0; + else if (WANT_MAPPED_A4_ONLY) want6 = 0; + + request = kvbuf_query("kskuku", "name", name, "ipv4", want4, "ipv6", want6); + if (request == NULL) return MACH_PORT_NULL; + + status = LI_async_start(&mp, proc, request, (void *)callback, my_context); + + kvbuf_free(request); return mp; } void getipnodebyname_async_cancel(mach_port_t port) { - _async_cancel(port); - return; + my_context_t *my_context; + + my_context = NULL; + + LI_async_call_cancel(port, (void **)&my_context); + + if (my_context != NULL) free(my_context); } void -getipnodebyname_async_handleReply(void *replyMsg) +getipnodebyname_async_handleReply(void *msg) { - int error = 0; - struct hostent *he = NULL; - a_requests_t *request = NULL; - static int proc4 = -1; + getipnodebyname_async_callback callback; + struct hostent *out; + uint32_t len, want; + int status, err; + kvarray_t *reply; + my_context_t *my_context; + void *context; + + callback = (getipnodebyname_async_callback)NULL; + my_context = NULL; + context = NULL; + len = 0; + reply = NULL; - if (_gethostbyname_async_handleReply(replyMsg, &request, &he, &error)) + status = LI_async_handle_reply(msg, &reply, (void **)&callback, (void **)&my_context); + if ((status != KERN_SUCCESS) || (reply == NULL)) { - /* - * we have an answer to provide - */ - 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 (status == MIG_REPLY_MISMATCH) return; + if (callback != NULL) { - /* - * no host found (yet), if requested we send a - * followup query to lookupd. - */ - 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; - } + if (my_context != NULL) context = my_context->user_context; + callback(NULL, NO_RECOVERY, context); + free(my_context); + return; } + } + + want = WANT_A4_ONLY; + if (my_context != NULL) + { + context = my_context->user_context; + want = my_context->want; + free(my_context); + } -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); - /* - * Note: it is up to the callback function to call - * freehostent(). - */ + out = extract_host(reply, want); + kvarray_free(reply); + + if (out == NULL) + { + err = HOST_NOT_FOUND; + callback(NULL, err, context); + return; } - return; + callback(out, 0, context); }