X-Git-Url: https://git.saurik.com/apple/libinfo.git/blobdiff_plain/a0865d6380e4ae001b2f00dbe4199477660b93d4..3e81ae21a7e2c2e07f2acbb16c9e9d1fd4a15b62:/lookup.subproj/lu_service.c diff --git a/lookup.subproj/lu_service.c b/lookup.subproj/lu_service.c index 4dc60e5..7d73677 100644 --- a/lookup.subproj/lu_service.c +++ b/lookup.subproj/lu_service.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,13 +29,21 @@ #include #include #include -#include "lookup.h" #include #include -#include "_lu_types.h" #include +#include +#include + +#include "_lu_types.h" +#include "lookup.h" #include "lu_utils.h" -#import + +static pthread_mutex_t _service_lock = PTHREAD_MUTEX_INITIALIZER; + +#define S_GET_NAME 1 +#define S_GET_PORT 2 +#define S_GET_ENT 3 extern struct servent *_old_getservbyport(); extern struct servent *_old_getservbyname(); @@ -44,285 +52,503 @@ extern void _old_setservent(); extern void _old_endservent(); extern void _old_setservfile(); -static lookup_state s_state = LOOKUP_CACHE; -static struct servent global_s; -static int global_free = 1; -static char *s_data = NULL; -static unsigned s_datalen; -static int s_nentries; -static int s_start = 1; -static XDR s_xdr; - static void -freeold(void) +free_service_data(struct servent *s) { char **aliases; - if (global_free == 1) return; + if (s == NULL) return; - if (global_s.s_name != NULL) free(global_s.s_name); - global_s.s_name = NULL; + if (s->s_name != NULL) free(s->s_name); + if (s->s_proto != NULL) free(s->s_proto); - if (global_s.s_proto != NULL) free(global_s.s_proto); - global_s.s_proto = NULL; - - aliases = global_s.s_aliases; + aliases = s->s_aliases; if (aliases != NULL) { while (*aliases != NULL) free(*aliases++); - free(global_s.s_aliases); - global_s.s_aliases = NULL; + free(s->s_aliases); } +} - global_free = 1; +static void +free_service(struct servent *s) +{ + if (s == NULL) return; + free_service_data(s); + free(s); } static void -convert_s(_lu_servent *lu_s) +free_lu_thread_info_service(void *x) +{ + struct lu_thread_info *tdata; + + if (x == NULL) return; + + tdata = (struct lu_thread_info *)x; + + if (tdata->lu_entry != NULL) + { + free_service((struct servent *)tdata->lu_entry); + tdata->lu_entry = NULL; + } + + _lu_data_free_vm_xdr(tdata); + + free(tdata); +} + +static struct servent * +extract_service(XDR *xdr, const char *proto) +{ + struct servent *s; + int i, j, nvals, nkeys, status; + char *key, **vals; + + if (xdr == NULL) return NULL; + + if (!xdr_int(xdr, &nkeys)) return NULL; + + s = (struct servent *)calloc(1, sizeof(struct servent)); + + for (i = 0; i < nkeys; i++) + { + key = NULL; + vals = NULL; + nvals = 0; + + status = _lu_xdr_attribute(xdr, &key, &vals, &nvals); + if (status < 0) + { + free_service(s); + return NULL; + } + + if (nvals == 0) + { + free(key); + continue; + } + + j = 0; + + if ((s->s_name == NULL) && (!strcmp("name", key))) + { + s->s_name = vals[0]; + if (nvals > 1) + { + s->s_aliases = (char **)calloc(nvals, sizeof(char *)); + for (j = 1; j < nvals; j++) s->s_aliases[j-1] = vals[j]; + } + j = nvals; + } + else if ((s->s_proto == NULL) && (!strcmp("protocol", key))) + { + if ((proto == NULL) || (proto[0] == '\0')) + { + s->s_proto = vals[0]; + j = 1; + } + else + { + s->s_proto = strdup(proto); + } + } + else if ((s->s_port == 0) && (!strcmp("port", key))) + { + s->s_port = htons(atoi(vals[0])); + } + + free(key); + if (vals != NULL) + { + for (; j < nvals; j++) free(vals[j]); + free(vals); + } + } + + if (s->s_name == NULL) s->s_name = strdup(""); + if (s->s_proto == NULL) s->s_proto = strdup(""); + if (s->s_aliases == NULL) s->s_aliases = (char **)calloc(1, sizeof(char *)); + + return s; +} + +static struct servent * +copy_service(struct servent *in) { int i, len; + struct servent *s; - freeold(); + if (in == NULL) return NULL; - global_s.s_name = strdup(lu_s->s_names.s_names_val[0]); + s = (struct servent *)calloc(1, sizeof(struct servent)); - len = lu_s->s_names.s_names_len - 1; - global_s.s_aliases = (char **)malloc((len + 1) * sizeof(char *)); + s->s_name = LU_COPY_STRING(in->s_name); + len = 0; + if (in->s_aliases != NULL) + { + for (len = 0; in->s_aliases[len] != NULL; len++); + } + + s->s_aliases = (char **)calloc(len + 1, sizeof(char *)); for (i = 0; i < len; i++) { - global_s.s_aliases[i] = strdup(lu_s->s_names.s_names_val[i+1]); + s->s_aliases[i] = strdup(in->s_aliases[i]); + } + + s->s_proto = LU_COPY_STRING(in->s_proto); + s->s_port = in->s_port; + + return s; +} + +static void +recycle_service(struct lu_thread_info *tdata, struct servent *in) +{ + struct servent *s; + + if (tdata == NULL) return; + s = (struct servent *)tdata->lu_entry; + + if (in == NULL) + { + free_service(s); + tdata->lu_entry = NULL; + } + + if (tdata->lu_entry == NULL) + { + tdata->lu_entry = in; + return; } - global_s.s_aliases[len] = NULL; + free_service_data(s); - if (lu_s->s_proto != NULL) global_s.s_proto = strdup(lu_s->s_proto); - global_s.s_port = lu_s->s_port; + s->s_name = in->s_name; + s->s_aliases = in->s_aliases; + s->s_proto = in->s_proto; + s->s_port = in->s_port; - global_free = 0; + free(in); } static struct servent * lu_getservbyport(int port, const char *proto) { - unsigned datalen; - _lu_servent_ptr lu_s; - XDR xdr; + struct servent *s; + unsigned int datalen; + XDR outxdr, inxdr; static int proc = -1; char output_buf[_LU_MAXLUSTRLEN + 3 * BYTES_PER_XDR_UNIT]; - unit lookup_buf[MAX_INLINE_UNITS]; - XDR outxdr; + char *lookup_buf; + int count; if (proc < 0) { if (_lookup_link(_lu_port, "getservbyport", &proc) != KERN_SUCCESS) { - return (NULL); + return NULL; } } /* Encode NULL for xmission to lookupd. */ - if (!proto) proto = ""; + if (proto == NULL) proto = ""; xdrmem_create(&outxdr, output_buf, sizeof(output_buf), XDR_ENCODE); - if (!xdr_int(&outxdr, &port) || !xdr__lu_string(&outxdr, &proto)) + if (!xdr_int(&outxdr, &port) || !xdr__lu_string(&outxdr, (_lu_string *)&proto)) { xdr_destroy(&outxdr); - return (NULL); + return NULL; } - datalen = MAX_INLINE_UNITS; - if (_lookup_one(_lu_port, proc, (unit *)output_buf, - xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen) + datalen = 0; + lookup_buf = NULL; + + if (_lookup_all(_lu_port, proc, (unit *)output_buf, + xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS) { xdr_destroy(&outxdr); - return (NULL); + return NULL; } xdr_destroy(&outxdr); datalen *= BYTES_PER_XDR_UNIT; - xdrmem_create(&xdr, lookup_buf, datalen, XDR_DECODE); - lu_s = NULL; - if (!xdr__lu_servent_ptr(&xdr, &lu_s) || (lu_s == NULL)) + if ((lookup_buf == NULL) || (datalen == 0)) return NULL; + + xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE); + + count = 0; + if (!xdr_int(&inxdr, &count)) + { + xdr_destroy(&inxdr); + vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen); + return NULL; + } + + if (count == 0) { - xdr_destroy(&xdr); - return (NULL); + xdr_destroy(&inxdr); + vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen); + return NULL; } - xdr_destroy(&xdr); + /* + * lookupd will only send back a reply for a service with the protocol specified + * if it finds a match. We pass the protocol name to extract_service, which + * copies the requested protocol name into the returned servent. This is a + * bit of a kludge, but since NetInfo / lookupd treat services as single entities + * with multiple protocols, we are forced to do some special-case handling. + */ + s = extract_service(&inxdr, proto); + xdr_destroy(&inxdr); + vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen); - convert_s(lu_s); - xdr_free(xdr__lu_servent_ptr, &lu_s); - return (&global_s); + return s; } static struct servent * lu_getservbyname(const char *name, const char *proto) { - unsigned datalen; - unit lookup_buf[MAX_INLINE_UNITS]; + struct servent *s; + unsigned int datalen; + char *lookup_buf; char output_buf[2 * (_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT)]; - XDR outxdr; - XDR inxdr; - _lu_servent_ptr lu_s; + XDR outxdr, inxdr; static int proc = -1; + int count; if (proc < 0) { if (_lookup_link(_lu_port, "getservbyname", &proc) != KERN_SUCCESS) { - return (NULL); + return NULL; } } /* Encode NULL for xmission to lookupd. */ - if (!proto) proto = ""; + if (proto == NULL) proto = ""; xdrmem_create(&outxdr, output_buf, sizeof(output_buf), XDR_ENCODE); - if (!xdr__lu_string(&outxdr, &name) || !xdr__lu_string(&outxdr, &proto)) + if (!xdr__lu_string(&outxdr, (_lu_string *)&name) || + !xdr__lu_string(&outxdr, (_lu_string *)&proto)) { xdr_destroy(&outxdr); - return (NULL); + return NULL; } - datalen = MAX_INLINE_UNITS; - if (_lookup_one(_lu_port, proc, (unit *)output_buf, - xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, lookup_buf, &datalen) + datalen = 0; + lookup_buf = NULL; + + if (_lookup_all(_lu_port, proc, (unit *)output_buf, + xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS) { xdr_destroy(&outxdr); - return (NULL); + return NULL; } xdr_destroy(&outxdr); datalen *= BYTES_PER_XDR_UNIT; - xdrmem_create(&inxdr, lookup_buf, datalen, - XDR_DECODE); - lu_s = NULL; - if (!xdr__lu_servent_ptr(&inxdr, &lu_s) || (lu_s == NULL)) + if ((lookup_buf == NULL) || (datalen == 0)) return NULL; + + xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE); + + count = 0; + if (!xdr_int(&inxdr, &count)) + { + xdr_destroy(&inxdr); + vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen); + return NULL; + } + + if (count == 0) { xdr_destroy(&inxdr); - return (NULL); + vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen); + return NULL; } + /* + * lookupd will only send back a reply for a service with the protocol specified + * if it finds a match. We pass the protocol name to extract_service, which + * copies the requested protocol name into the returned servent. This is a + * bit of a kludge, but since NetInfo / lookupd treat services as single entities + * with multiple protocols, we are forced to do some special-case handling. + */ + s = extract_service(&inxdr, proto); xdr_destroy(&inxdr); + vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen); - convert_s(lu_s); - xdr_free(xdr__lu_servent_ptr, &lu_s); - return (&global_s); + return s; } static void lu_endservent() { - s_nentries = 0; - if (s_data != NULL) - { - freeold(); - vm_deallocate(mach_task_self(), (vm_address_t)s_data, s_datalen); - s_data = NULL; - } + struct lu_thread_info *tdata; + + tdata = _lu_data_create_key(_lu_data_key_service, free_lu_thread_info_service); + _lu_data_free_vm_xdr(tdata); } static void lu_setservent() { lu_endservent(); - s_start = 1; } static struct servent * lu_getservent() { + struct servent *s; static int proc = -1; - _lu_servent lu_s; + struct lu_thread_info *tdata; - if (s_start == 1) + tdata = _lu_data_create_key(_lu_data_key_service, free_lu_thread_info_service); + if (tdata == NULL) + { + tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info)); + _lu_data_set_key(_lu_data_key_service, tdata); + } + + if (tdata->lu_vm == NULL) { - s_start = 0; - if (proc < 0) { if (_lookup_link(_lu_port, "getservent", &proc) != KERN_SUCCESS) { lu_endservent(); - return (NULL); + return NULL; } } - if (_lookup_all(_lu_port, proc, NULL, 0, &s_data, &s_datalen) - != KERN_SUCCESS) + if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS) { lu_endservent(); - return (NULL); + return NULL; } -#ifdef NOTDEF -/* NOTDEF because OOL buffers are counted in bytes with untyped IPC */ - s_datalen *= BYTES_PER_XDR_UNIT; -#endif + /* mig stubs measure size in words (4 bytes) */ + tdata->lu_vm_length *= 4; + + if (tdata->lu_xdr != NULL) + { + xdr_destroy(tdata->lu_xdr); + free(tdata->lu_xdr); + } + tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR)); - xdrmem_create(&s_xdr, s_data, s_datalen, - XDR_DECODE); - if (!xdr_int(&s_xdr, &s_nentries)) + xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE); + if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor)) { - xdr_destroy(&s_xdr); lu_endservent(); - return (NULL); + return NULL; } } - if (s_nentries == 0) + if (tdata->lu_vm_cursor == 0) { - xdr_destroy(&s_xdr); lu_endservent(); - return (NULL); + return NULL; } - bzero(&lu_s, sizeof(lu_s)); - if (!xdr__lu_servent(&s_xdr, &lu_s)) + s = extract_service(tdata->lu_xdr, NULL); + if (s == NULL) { - xdr_destroy(&s_xdr); lu_endservent(); - return (NULL); + return NULL; + } + + tdata->lu_vm_cursor--; + + return s; +} + +static struct servent * +getserv(const char *name, const char *proto, int port, int source) +{ + struct servent *res = NULL; + struct lu_thread_info *tdata; + + tdata = _lu_data_create_key(_lu_data_key_service, free_lu_thread_info_service); + if (tdata == NULL) + { + tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info)); + _lu_data_set_key(_lu_data_key_service, tdata); + } + + if (_lu_running()) + { + switch (source) + { + case S_GET_NAME: + res = lu_getservbyname(name, proto); + break; + case S_GET_PORT: + res = lu_getservbyport(port, proto); + break; + case S_GET_ENT: + res = lu_getservent(); + break; + default: res = NULL; + } + } + else + { + pthread_mutex_lock(&_service_lock); + switch (source) + { + case S_GET_NAME: + res = copy_service(_old_getservbyname(name, proto)); + break; + case S_GET_PORT: + res = copy_service(_old_getservbyport(port, proto)); + break; + case S_GET_ENT: + res = copy_service(_old_getservent()); + break; + default: res = NULL; + } + pthread_mutex_unlock(&_service_lock); } - s_nentries--; - convert_s(&lu_s); - xdr_free(xdr__lu_servent, &lu_s); - return (&global_s); + recycle_service(tdata, res); + return (struct servent *)tdata->lu_entry; } struct servent * getservbyport(int port, const char *proto) { - LOOKUP2(lu_getservbyport, _old_getservbyport, port, proto, struct servent); + return getserv(NULL, proto, port, S_GET_PORT); } struct servent * getservbyname(const char *name, const char *proto) { - LOOKUP2(lu_getservbyname, _old_getservbyname, name, proto, - struct servent); + return getserv(name, proto, 0, S_GET_NAME); } struct servent * getservent(void) { - GETENT(lu_getservent, _old_getservent, &s_state, struct servent); + return getserv(NULL, NULL, 0, S_GET_ENT); } void setservent(int stayopen) { - SETSTATE(lu_setservent, _old_setservent, &s_state, stayopen); + if (_lu_running()) lu_setservent(); + else _old_setservent(); } void endservent(void) { - UNSETSTATE(lu_endservent, _old_endservent, &s_state); + if (_lu_running()) lu_endservent(); + else _old_endservent(); }