2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1999 by Sun Microsystems, Inc.
2N/A * All rights reserved.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <syslog.h>
2N/A#include <slp-internal.h>
2N/A
2N/Astatic SLPBoolean UnpackSrvTypesReply(slp_handle_impl_t *, char *,
2N/A SLPSrvTypeCallback, void *,
2N/A void **, int *);
2N/Astatic SLPError slp_packSrvTypeRqst(slp_handle_impl_t *, const char *);
2N/Astatic char *collate_types(char *, void **, int *, int);
2N/Astatic char *build_types_list(void *);
2N/Astatic void collect_types(void *, VISIT, int, void *);
2N/A
2N/ASLPError SLPFindSrvTypes(SLPHandle hSLP, const char *pcNamingAuthority,
2N/A const char *pcScopeList,
2N/A SLPSrvTypeCallback callback, void *pvUser) {
2N/A SLPError err;
2N/A
2N/A if (!hSLP || !pcNamingAuthority || !pcScopeList ||
2N/A !*pcScopeList || !callback) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((strlen(pcNamingAuthority) > SLP_MAX_STRINGLEN) ||
2N/A (strlen(pcScopeList) > SLP_MAX_STRINGLEN)) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((err = slp_start_call(hSLP)) != SLP_OK)
2N/A return (err);
2N/A
2N/A /* format params into msgBuf */
2N/A err = slp_packSrvTypeRqst(hSLP, pcNamingAuthority);
2N/A
2N/A if (err == SLP_OK)
2N/A err = slp_ua_common(hSLP, pcScopeList,
2N/A (SLPGenericAppCB *) callback, pvUser,
2N/A (SLPMsgReplyCB *) UnpackSrvTypesReply);
2N/A
2N/A if (err != SLP_OK)
2N/A slp_end_call(hSLP);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astatic SLPBoolean UnpackSrvTypesReply(slp_handle_impl_t *hp, char *reply,
2N/A SLPSrvTypeCallback cb, void *cookie,
2N/A void **collator, int *numResults) {
2N/A char *pcSrvTypes;
2N/A SLPError errCode;
2N/A unsigned short protoErrCode;
2N/A size_t off, len;
2N/A int maxResults = slp_get_maxResults();
2N/A SLPBoolean cont = SLP_TRUE;
2N/A
2N/A if (!reply) {
2N/A /* no more results */
2N/A if (!hp->async) {
2N/A pcSrvTypes = build_types_list(*collator);
2N/A }
2N/A
2N/A if (!hp->async && pcSrvTypes) {
2N/A /* synchronous case */
2N/A cb(hp, pcSrvTypes, SLP_OK, cookie);
2N/A free(pcSrvTypes);
2N/A }
2N/A cb(hp, NULL, SLP_LAST_CALL, cookie);
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A /* parse reply into params */
2N/A len = slp_get_length(reply);
2N/A off = SLP_HDRLEN + slp_get_langlen(reply);
2N/A /* error code */
2N/A if (slp_get_sht(reply, len, &off, &protoErrCode) != SLP_OK)
2N/A return (SLP_TRUE);
2N/A /* internal errors should have been filtered out by the net code */
2N/A if ((errCode = slp_map_err(protoErrCode)) != SLP_OK) {
2N/A return (cb(hp, NULL, errCode, cookie));
2N/A }
2N/A
2N/A /* types string */
2N/A if (slp_get_string(reply, len, &off, &pcSrvTypes) != SLP_OK)
2N/A return (SLP_TRUE);
2N/A
2N/A /* collate the types for sync behavior */
2N/A if (!hp->async) {
2N/A pcSrvTypes = collate_types(pcSrvTypes, collator,
2N/A numResults, maxResults);
2N/A if (!pcSrvTypes)
2N/A return (SLP_TRUE);
2N/A } else {
2N/A /* async; invoke cb */
2N/A cont = cb((SLPHandle) hp, pcSrvTypes, errCode, cookie);
2N/A }
2N/A
2N/A /* cleanup */
2N/A free(pcSrvTypes);
2N/A
2N/A /* check maxResults */
2N/A if (!hp->internal_call && *numResults == maxResults) {
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A return (cont);
2N/A}
2N/A
2N/Astatic SLPError slp_packSrvTypeRqst(slp_handle_impl_t *hp, const char *na) {
2N/A SLPError err;
2N/A size_t len, nalen, msgLen, tmplen;
2N/A int all_nas;
2N/A slp_msg_t *msg = &(hp->msg);
2N/A
2N/A /*
2N/A * Allocate iovec for the message. A SrvTypeRqst is layed out thus:
2N/A * 0: header
2N/A * 1: prlist length
2N/A * 2: prlist (filled in later by networking code)
2N/A * 3: na
2N/A * 4: scopes length
2N/A * 5: scopes (filled in later by networking code)
2N/A */
2N/A if (!(msg->iov = calloc(6, sizeof (*(msg->iov))))) {
2N/A slp_err(LOG_CRIT, 0, "slp_packSrvTypeRqst", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A msg->iovlen = 6;
2N/A
2N/A /* calculate msg length */
2N/A all_nas = strcmp(na, "*") == 0 ? 1 : 0;
2N/A if (all_nas) {
2N/A nalen = 0;
2N/A } else {
2N/A nalen = strlen(na);
2N/A }
2N/A nalen += 2;
2N/A
2N/A msgLen = 2 + /* prlist length */
2N/A nalen + /* NA string */
2N/A 2; /* Scope string length */
2N/A
2N/A if (!(msg->msg = calloc(1, msgLen))) {
2N/A free(msg->iov);
2N/A slp_err(LOG_CRIT, 0, "slp_packSrvTypeRqst", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A
2N/A /* set pointer to PR list and scope list length spaces */
2N/A msg->prlistlen.iov_base = msg->msg;
2N/A msg->prlistlen.iov_len = 2;
2N/A msg->iov[1].iov_base = msg->msg;
2N/A msg->iov[1].iov_len = 2;
2N/A
2N/A msg->scopeslen.iov_base = msg->msg + 2;
2N/A msg->scopeslen.iov_len = 2;
2N/A msg->iov[4].iov_base = msg->msg + 2;
2N/A msg->iov[4].iov_len = 2;
2N/A
2N/A /* set up the scopes and prlist pointers into iov */
2N/A msg->prlist = &(msg->iov[2]);
2N/A msg->scopes = &(msg->iov[5]);
2N/A
2N/A len = 4;
2N/A
2N/A /* set up NA string in iovec */
2N/A msg->iov[3].iov_base = msg->msg + len;
2N/A tmplen = len;
2N/A
2N/A if (all_nas) {
2N/A err = slp_add_sht(msg->msg, msgLen, 0xffff, &len);
2N/A } else {
2N/A err = slp_add_string(msg->msg, msgLen, na, &len);
2N/A }
2N/A msg->iov[3].iov_len = len - tmplen;
2N/A
2N/A hp->fid = SRVTYPERQST;
2N/A if (err == SLP_OK) {
2N/A return (SLP_OK);
2N/A }
2N/A
2N/A /* else error */
2N/A free(msg->iov);
2N/A free(msg->msg);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Using the collator, determines which types in the types list
2N/A * have already been recieved, and composes a new list of the remaining
2N/A * (unique) types. If there are no unique types, returns NULL;
2N/A * types is destructively modified.
2N/A */
2N/Astatic char *collate_types(char *types, void **collator,
2N/A int *numResults, int maxResults) {
2N/A char *p, *s, **res, *utypes = NULL;
2N/A
2N/A /* walk through the types list */
2N/A p = types;
2N/A for (s = types; p && *numResults != maxResults; s = p) {
2N/A p = slp_utf_strchr(s, ',');
2N/A if (p)
2N/A *p++ = 0;
2N/A if (!(s = strdup(s))) {
2N/A free(types);
2N/A if (utypes) free(utypes);
2N/A slp_err(LOG_CRIT, 0, "collate_types", "out of memory");
2N/A return (NULL);
2N/A }
2N/A /* search the tree for this type */
2N/A res = slp_tsearch((void *) s, collator,
2N/A (int (*)(const void *, const void *)) slp_strcasecmp);
2N/A if (*res == s) {
2N/A /* first time we've encountered this type */
2N/A slp_add2list(s, &utypes, SLP_FALSE);
2N/A (*numResults)++;
2N/A } else {
2N/A /* else already in tree */
2N/A free(s);
2N/A }
2N/A }
2N/A free(types);
2N/A return (utypes);
2N/A}
2N/A
2N/A/*
2N/A * This is used after all types have been collated into the tree.
2N/A * It walks through the tree, composing a list from all the types in
2N/A * the tree, and freeing each node of the tree as it goes.
2N/A * Returns the list, or NULL if the tree is empty.
2N/A */
2N/A/* the walk action function: */
2N/A/*ARGSUSED*/
2N/Astatic void collect_types(void *node, VISIT order, int level, void *cookie) {
2N/A char **types = (char **)cookie;
2N/A
2N/A if (order == endorder || order == leaf) {
2N/A char *t = *(char **)node;
2N/A slp_add2list(t, types, SLP_FALSE);
2N/A free(t);
2N/A free(node);
2N/A }
2N/A}
2N/A
2N/A/* the walk driver: */
2N/Astatic char *build_types_list(void *collator) {
2N/A char *types = NULL;
2N/A
2N/A if (!collator)
2N/A return (NULL);
2N/A slp_twalk(collator, collect_types, 0, (void *) &types);
2N/A return (types);
2N/A}