diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libslp/clib/SLPFindAttrs.c | |
download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libslp/clib/SLPFindAttrs.c')
-rw-r--r-- | usr/src/lib/libslp/clib/SLPFindAttrs.c | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/usr/src/lib/libslp/clib/SLPFindAttrs.c b/usr/src/lib/libslp/clib/SLPFindAttrs.c new file mode 100644 index 0000000000..799855d8bd --- /dev/null +++ b/usr/src/lib/libslp/clib/SLPFindAttrs.c @@ -0,0 +1,588 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <syslog.h> +#include <slp-internal.h> + +struct attr_node { + char *tag, *val; +}; + +static SLPError slp_packAttrRqst(slp_handle_impl_t *, const char *, + const char *); +static int compare_tags(const void *, const void *); +static void collate_attrs(char *, void **, int *, int); +static void parens_attr(char *, void **, int *); +static void merge_attrs(struct attr_node *, char *); +static char *build_attrs_list(void *collator); +static void collect_attrs(void *, VISIT, int, void *); +static SLPBoolean unpackDAAdvert_attr(slp_handle_impl_t *, char *, + SLPAttrCallback, void *, + void **, int *); +static SLPBoolean unpackSAAdvert_attr(slp_handle_impl_t *, char *, + SLPAttrCallback, void *, + void **, int *); + +SLPError SLPFindAttrs(SLPHandle hSLP, const char *pcURL, const char *pcScope, + const char *pcAttrIds, + SLPAttrCallback callback, void *pvUser) { + SLPError err; + int wantSAAdvert = + strcasecmp(pcURL, "service:service-agent") == 0; + int wantDAAdvert = + strcasecmp(pcURL, "service:directory-agent") == 0; + int isSpecial = wantSAAdvert || wantDAAdvert; + SLPMsgReplyCB *unpack_cb; + + + if (!hSLP || !pcURL || !pcScope || (!*pcScope && !isSpecial) || + !pcAttrIds || !callback) { + return (SLP_PARAMETER_BAD); + } + + if ((strlen(pcURL) > SLP_MAX_STRINGLEN) || + (strlen(pcScope) > SLP_MAX_STRINGLEN) || + (strlen(pcAttrIds) > SLP_MAX_STRINGLEN)) { + return (SLP_PARAMETER_BAD); + } + + if ((err = slp_start_call(hSLP)) != SLP_OK) + return (err); + + /* Special packer and unpacker for DA and SA solicitations */ + if (wantDAAdvert) { + unpack_cb = (SLPMsgReplyCB *)unpackDAAdvert_attr; + err = slp_packSrvRqst(pcURL, "", hSLP); + ((slp_handle_impl_t *)hSLP)->force_multicast = SLP_TRUE; + } else if (wantSAAdvert) { + unpack_cb = (SLPMsgReplyCB *)unpackSAAdvert_attr; + err = slp_packSrvRqst(pcURL, "", hSLP); + ((slp_handle_impl_t *)hSLP)->force_multicast = SLP_TRUE; + } else { + /* normal service request */ + unpack_cb = (SLPMsgReplyCB *)slp_UnpackAttrReply; + /* format params into msgBuf */ + err = slp_packAttrRqst(hSLP, pcURL, pcAttrIds); + } + + if (err == SLP_OK) + err = slp_ua_common(hSLP, pcScope, + (SLPGenericAppCB *) callback, pvUser, + unpack_cb); + + if (err != SLP_OK) + slp_end_call(hSLP); + + return (err); +} + +SLPBoolean slp_UnpackAttrReply(slp_handle_impl_t *hp, char *reply, + SLPAttrCallback cb, void *cookie, + void **collator, int *numResults) { + char *pcAttrList; + SLPError errCode; + unsigned short protoErrCode; + size_t len, off; + int maxResults = slp_get_maxResults(); + SLPBoolean cont = SLP_TRUE; + int auth_cnt; + size_t tbv_len; + char *attr_tbv; + + if (!reply) { + /* no more results */ + if (!hp->async) { + pcAttrList = build_attrs_list(*collator); + } + + if (!hp->async && pcAttrList) { + cb(hp, pcAttrList, SLP_OK, cookie); + free(pcAttrList); + } + cb(hp, NULL, SLP_LAST_CALL, cookie); + return (SLP_FALSE); + } + + /* parse reply into params */ + len = slp_get_length(reply); + off = SLP_HDRLEN + slp_get_langlen(reply); + /* err code */ + if (slp_get_sht(reply, len, &off, &protoErrCode) != SLP_OK) + return (SLP_TRUE); + /* internal errors should have been filtered out by the net code */ + if ((errCode = slp_map_err(protoErrCode)) != SLP_OK) { + return (cb(hp, NULL, errCode, cookie)); + } + + /* attr list */ + attr_tbv = reply + off; + tbv_len = off; + if (slp_get_string(reply, len, &off, &pcAttrList) != SLP_OK) + return (SLP_TRUE); + tbv_len = off - tbv_len; + + /* number of attr auths */ + if (slp_get_byte(reply, len, &off, &auth_cnt) != SLP_OK) { + goto cleanup; + } + + /* get and verify auth blocks */ + if ((!hp->internal_call && slp_get_security_on()) || auth_cnt > 0) { + size_t abLen = 0; + struct iovec iov[1]; + + iov[0].iov_base = attr_tbv; + iov[0].iov_len = tbv_len; + + if (slp_verify(iov, 1, + reply + off, + len - off, + auth_cnt, + &abLen) != SLP_OK) { + goto cleanup; + } + } + + /* collate */ + if (!hp->async) { + collate_attrs(pcAttrList, collator, numResults, maxResults); + } else { + /* async: invoke cb */ + cont = cb((SLPHandle) hp, pcAttrList, errCode, cookie); + (*numResults)++; + } + +cleanup: + free(pcAttrList); + + /* check maxResults */ + if (!hp->internal_call && *numResults == maxResults) { + return (SLP_FALSE); + } + + return (cont); +} + +/* + * unpackDAAdvert_attr follows the same logic stream as UnpackAttrReply, + * except that reply contains a DAAdvert. + */ +static SLPBoolean unpackDAAdvert_attr(slp_handle_impl_t *hp, char *reply, + SLPAttrCallback cb, void *cookie, + void **collator, int *numResults) { + char *surl, *scopes, *attrs, *spis; + SLPBoolean cont = SLP_TRUE; + SLPError errCode; + int maxResults = slp_get_maxResults(); + + if (!reply) { + /* no more results */ + if (!hp->async) { + attrs = build_attrs_list(*collator); + } + + if (!hp->async && attrs) { + cb(hp, attrs, SLP_OK, cookie); + free(attrs); + } + cb(hp, NULL, SLP_LAST_CALL, cookie); + return (SLP_FALSE); + } + + if (slp_unpackDAAdvert(reply, &surl, &scopes, &attrs, &spis, &errCode) + != SLP_OK) { + return (SLP_TRUE); + } + if (errCode != SLP_OK) { + return (cb(hp, NULL, errCode, cookie)); + } + + /* collate */ + if (!hp->async) { + collate_attrs(attrs, collator, numResults, maxResults); + } else { + /* async: invoke cb */ + cont = cb((SLPHandle) hp, attrs, errCode, cookie); + (*numResults)++; + } + + /* cleanup */ + free(surl); + free(scopes); + free(attrs); + free(spis); + + /* check maxResults */ + if (!hp->internal_call && *numResults == maxResults) { + return (SLP_FALSE); + } + + return (cont); +} + +/* + * unpackSAAdvert_attr follows the same logic stream as UnpackAttrReply, + * except that reply contains an SAAdvert. + */ +static SLPBoolean unpackSAAdvert_attr(slp_handle_impl_t *hp, char *reply, + SLPAttrCallback cb, void *cookie, + void **collator, int *numResults) { + char *surl, *scopes, *attrs; + SLPBoolean cont = SLP_TRUE; + int maxResults = slp_get_maxResults(); + + if (!reply) { + /* no more results */ + if (!hp->async) { + attrs = build_attrs_list(*collator); + } + + if (!hp->async && attrs) { + cb(hp, attrs, SLP_OK, cookie); + free(attrs); + } + cb(hp, NULL, SLP_LAST_CALL, cookie); + return (SLP_FALSE); + } + + if (slp_unpackSAAdvert(reply, &surl, &scopes, &attrs) != SLP_OK) { + return (SLP_TRUE); + } + + /* collate */ + if (!hp->async) { + collate_attrs(attrs, collator, numResults, maxResults); + } else { + /* async: invoke cb */ + cont = cb((SLPHandle) hp, attrs, SLP_OK, cookie); + (*numResults)++; + } + + /* cleanup */ + free(surl); + free(scopes); + free(attrs); + + /* check maxResults */ + if (!hp->internal_call && *numResults == maxResults) { + return (SLP_FALSE); + } + + return (cont); +} + +static SLPError slp_packAttrRqst(slp_handle_impl_t *hp, const char *url, + const char *ids) { + SLPError err; + size_t len, tmplen, msgLen; + slp_msg_t *msg = &(hp->msg); + char *spi = NULL; + + if (slp_get_security_on()) { + spi = (char *)SLPGetProperty(SLP_CONFIG_SPI); + } + + if (!spi || !*spi) { + spi = ""; + } + + /* + * Allocate iovec for the messge. An AttrRqst is layed out thus: + * 0: header + * 1: prlist length + * 2: prlist (filled in later by networking code) + * 3: URL string + * 4: scopes length + * 5: scopes (filled in later by networking code) + * 6: tag list string and SPI string + */ + if (!(msg->iov = calloc(7, sizeof (*(msg->iov))))) { + slp_err(LOG_CRIT, 0, "slp_packAttrRqst", "out of memory"); + return (SLP_MEMORY_ALLOC_FAILED); + } + msg->iovlen = 7; + + /* calculate msg length */ + msgLen = 2 + /* prlist length */ + 2 + strlen(url) + /* URL */ + 2 + /* scope list length */ + 2 + strlen(ids) + /* tag list */ + 2 + strlen(spi); /* SPI string */ + + if (!(msg->msg = calloc(1, msgLen))) { + free(msg->iov); + slp_err(LOG_CRIT, 0, "slp_packAttrRqst", "out of memory"); + return (SLP_MEMORY_ALLOC_FAILED); + } + + /* set pointer to PR list and scope list length spaces */ + msg->prlistlen.iov_base = msg->msg; + msg->prlistlen.iov_len = 2; + msg->iov[1].iov_base = msg->msg; + msg->iov[1].iov_len = 2; + + msg->scopeslen.iov_base = msg->msg + 2; + msg->scopeslen.iov_len = 2; + msg->iov[4].iov_base = msg->msg + 2; + msg->iov[4].iov_len = 2; + + /* set up the scopes and prlist pointers into iov */ + msg->prlist = &(msg->iov[2]); + msg->scopes = &(msg->iov[5]); + + len = 4; + + /* Add URL string */ + msg->iov[3].iov_base = msg->msg + len; + tmplen = len; + + err = slp_add_string(msg->msg, msgLen, url, &len); + msg->iov[3].iov_len = len - tmplen; + + if (err != SLP_OK) + goto error; + + /* Add tag list */ + msg->iov[6].iov_base = msg->msg + len; + tmplen = len; + + err = slp_add_string(msg->msg, msgLen, ids, &len); + + if (err != SLP_OK) + goto error; + + /* SPI string */ + err = slp_add_string(msg->msg, msgLen, spi, &len); + + msg->iov[6].iov_len = len - tmplen; + + hp->fid = ATTRRQST; + if (err == SLP_OK) { + return (SLP_OK); + } + + /* else error */ +error: + free(msg->iov); + free(msg->msg); + + return (err); +} + +SLPError slp_packAttrRqst_single(const char *url, + const char *scopes, + const char *ids, + char **msg, + const char *lang) { + SLPError err; + size_t len, msgLen; + + msgLen = + SLP_HDRLEN + strlen(lang) + 2 + + 2 + strlen(url) + + 2 + strlen(scopes) + + 2 + strlen(ids) + + 2; /* No SPI string for internal calls */ + + if (!(*msg = calloc(msgLen, 1))) { + slp_err(LOG_CRIT, 0, "slp_packAttrRqst_single", "out of memory"); + return (SLP_MEMORY_ALLOC_FAILED); + } + + len = 0; + err = slp_add_header(lang, *msg, msgLen, ATTRRQST, msgLen, &len); + + len += 2; /* empty PR list */ + + if (err == SLP_OK) { + err = slp_add_string(*msg, msgLen, url, &len); + } + if (err == SLP_OK) { + err = slp_add_string(*msg, msgLen, scopes, &len); + } + if (err == SLP_OK) { + err = slp_add_string(*msg, msgLen, ids, &len); + } + /* empty SPI */ + if (err == SLP_OK) { + err = slp_add_string(*msg, msgLen, "", &len); + } + + return (err); +} + +static int compare_tags(const void *n1, const void *n2) { + return slp_strcasecmp( + ((struct attr_node *)n1)->tag, + ((struct attr_node *)n2)->tag); +} + +static void merge_attrs(struct attr_node *n, char *vals) { + char *p, *v; + + for (p = v = vals; p; v = p) { + p = slp_utf_strchr(v, ','); + if (p) + *p++ = 0; + slp_add2list(v, &(n->val), SLP_TRUE); + } +} + +static void parens_attr(char *attr, void **collator, int *numResults) { + char *open_paren, *close_paren, *equals; + struct attr_node *n, **res; + + open_paren = attr + 1; + close_paren = slp_utf_strchr(open_paren, ')'); + if (!close_paren) + return; /* skip bad attr list */ + + *close_paren = 0; + if (!(equals = slp_utf_strchr(open_paren, '='))) + return; + + *equals++ = 0; + + if (!(n = malloc(sizeof (*n)))) { + slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory"); + return; + } + + if (!(n->tag = strdup(open_paren))) { + free(n); + slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory"); + return; + } + n->val = NULL; + + res = slp_tsearch(n, collator, compare_tags); + + if (*res != n) { + merge_attrs(*res, equals); + free(n->tag); free(n); + } else { + /* not found; populate new attr node */ + (*numResults)++; + if (!(n->val = strdup(equals))) { + slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory"); + return; + } + } +} + +static void collate_attrs(char *attrs, void **collator, + int *numResults, int maxResults) { + char *start, *end; + struct attr_node *n, **res; + + for (start = attrs; + start && + *start && + *numResults != maxResults; + start = end) { + if (*start == ',') start++; + if (*start == '(') { + /* form of (tag=val,val) */ + if (!(end = slp_utf_strchr(start, ')'))) + return; /* skip bad attr */ + parens_attr(start, collator, numResults); + end++; + continue; + } + end = slp_utf_strchr(start, ','); + if (end) + *end++ = 0; + /* create a new node with the tag only */ + if (!(n = malloc(sizeof (*n)))) { + slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory"); + return; + } + + if (!(n->tag = strdup(start))) { + free(n); + slp_err(LOG_CRIT, 0, "collate_attrs", "out of memory"); + return; + } + n->val = NULL; + res = slp_tsearch(n, collator, compare_tags); + if (*res != n) { + /* already in the tree, so just free resources */ + free(n->tag); free(n); + } + (*numResults)++; + } +} + +static char *build_attrs_list(void *collator) { + char *answer = NULL; + + if (!collator) + return (NULL); + + slp_twalk(collator, collect_attrs, 0, &answer); + return (answer); +} + +/*ARGSUSED*/ +static void collect_attrs(void *node, VISIT order, int level, void *cookie) { + struct attr_node *n; + char *attr, *p, **answer = (char **)cookie; + + if (order == endorder || order == leaf) { + n = *(struct attr_node **)node; + if (!n->val) { + /* no values, so no parens */ + if (!(attr = malloc(strlen(n->tag) + 1))) { + slp_err(LOG_CRIT, 0, "collect_attrs", + "out of memory"); + return; + } + (void) strcpy(attr, n->tag); + } else { + if (!(attr = malloc(1 + strlen(n->tag) + 1 + + strlen(n->val) + 2))) { + slp_err(LOG_CRIT, 0, "collect_attrs", + "out of memory"); + return; + } + /* build attr string */ + p = attr; + *p++ = '('; + (void) strcpy(p, n->tag); p += strlen(n->tag); + *p++ = '='; + (void) strcpy(p, n->val); p += strlen(n->val); + *p++ = ')'; *p = 0; + } + + slp_add2list(attr, answer, SLP_FALSE); + free(attr); + free(n->tag); if (n->val) free(n->val); free(n); + free(node); + } +} |