1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1999 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <syslog.h>
30*7c478bd9Sstevel@tonic-gate #include <slp-internal.h>
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate static SLPBoolean UnpackSrvTypesReply(slp_handle_impl_t *, char *,
33*7c478bd9Sstevel@tonic-gate 					SLPSrvTypeCallback, void *,
34*7c478bd9Sstevel@tonic-gate 					void **, int *);
35*7c478bd9Sstevel@tonic-gate static SLPError slp_packSrvTypeRqst(slp_handle_impl_t *, const char *);
36*7c478bd9Sstevel@tonic-gate static char *collate_types(char *, void **, int *, int);
37*7c478bd9Sstevel@tonic-gate static char *build_types_list(void *);
38*7c478bd9Sstevel@tonic-gate static void collect_types(void *, VISIT, int, void *);
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate SLPError SLPFindSrvTypes(SLPHandle hSLP, const char *pcNamingAuthority,
41*7c478bd9Sstevel@tonic-gate 				const char *pcScopeList,
42*7c478bd9Sstevel@tonic-gate 				SLPSrvTypeCallback callback, void *pvUser) {
43*7c478bd9Sstevel@tonic-gate 	SLPError err;
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate 	if (!hSLP || !pcNamingAuthority || !pcScopeList ||
46*7c478bd9Sstevel@tonic-gate 	    !*pcScopeList || !callback) {
47*7c478bd9Sstevel@tonic-gate 		return (SLP_PARAMETER_BAD);
48*7c478bd9Sstevel@tonic-gate 	}
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate 	if ((strlen(pcNamingAuthority) > SLP_MAX_STRINGLEN) ||
51*7c478bd9Sstevel@tonic-gate 	    (strlen(pcScopeList) > SLP_MAX_STRINGLEN)) {
52*7c478bd9Sstevel@tonic-gate 	    return (SLP_PARAMETER_BAD);
53*7c478bd9Sstevel@tonic-gate 	}
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate 	if ((err = slp_start_call(hSLP)) != SLP_OK)
56*7c478bd9Sstevel@tonic-gate 		return (err);
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate 	/* format params into msgBuf */
59*7c478bd9Sstevel@tonic-gate 	err = slp_packSrvTypeRqst(hSLP, pcNamingAuthority);
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	if (err == SLP_OK)
62*7c478bd9Sstevel@tonic-gate 		err = slp_ua_common(hSLP, pcScopeList,
63*7c478bd9Sstevel@tonic-gate 				    (SLPGenericAppCB *) callback, pvUser,
64*7c478bd9Sstevel@tonic-gate 				    (SLPMsgReplyCB *) UnpackSrvTypesReply);
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate 	if (err != SLP_OK)
67*7c478bd9Sstevel@tonic-gate 		slp_end_call(hSLP);
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 	return (err);
70*7c478bd9Sstevel@tonic-gate }
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate static SLPBoolean UnpackSrvTypesReply(slp_handle_impl_t *hp, char *reply,
73*7c478bd9Sstevel@tonic-gate 					SLPSrvTypeCallback cb, void *cookie,
74*7c478bd9Sstevel@tonic-gate 					void **collator, int *numResults) {
75*7c478bd9Sstevel@tonic-gate 	char *pcSrvTypes;
76*7c478bd9Sstevel@tonic-gate 	SLPError errCode;
77*7c478bd9Sstevel@tonic-gate 	unsigned short protoErrCode;
78*7c478bd9Sstevel@tonic-gate 	size_t off, len;
79*7c478bd9Sstevel@tonic-gate 	int maxResults = slp_get_maxResults();
80*7c478bd9Sstevel@tonic-gate 	SLPBoolean cont = SLP_TRUE;
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	if (!reply) {
83*7c478bd9Sstevel@tonic-gate 		/* no more results */
84*7c478bd9Sstevel@tonic-gate 		if (!hp->async) {
85*7c478bd9Sstevel@tonic-gate 		    pcSrvTypes = build_types_list(*collator);
86*7c478bd9Sstevel@tonic-gate 		}
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 		if (!hp->async && pcSrvTypes) {
89*7c478bd9Sstevel@tonic-gate 		    /* synchronous case */
90*7c478bd9Sstevel@tonic-gate 		    cb(hp, pcSrvTypes, SLP_OK, cookie);
91*7c478bd9Sstevel@tonic-gate 		    free(pcSrvTypes);
92*7c478bd9Sstevel@tonic-gate 		}
93*7c478bd9Sstevel@tonic-gate 		cb(hp, NULL, SLP_LAST_CALL, cookie);
94*7c478bd9Sstevel@tonic-gate 		return (SLP_FALSE);
95*7c478bd9Sstevel@tonic-gate 	}
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	/* parse reply into params */
98*7c478bd9Sstevel@tonic-gate 	len = slp_get_length(reply);
99*7c478bd9Sstevel@tonic-gate 	off = SLP_HDRLEN + slp_get_langlen(reply);
100*7c478bd9Sstevel@tonic-gate 	/* error code */
101*7c478bd9Sstevel@tonic-gate 	if (slp_get_sht(reply, len, &off, &protoErrCode) != SLP_OK)
102*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
103*7c478bd9Sstevel@tonic-gate 	/* internal errors should have been filtered out by the net code */
104*7c478bd9Sstevel@tonic-gate 	if ((errCode = slp_map_err(protoErrCode)) != SLP_OK) {
105*7c478bd9Sstevel@tonic-gate 		return (cb(hp, NULL, errCode, cookie));
106*7c478bd9Sstevel@tonic-gate 	}
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	/* types string */
109*7c478bd9Sstevel@tonic-gate 	if (slp_get_string(reply, len, &off, &pcSrvTypes) != SLP_OK)
110*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	/* collate the types for sync behavior */
113*7c478bd9Sstevel@tonic-gate 	if (!hp->async) {
114*7c478bd9Sstevel@tonic-gate 	    pcSrvTypes = collate_types(pcSrvTypes, collator,
115*7c478bd9Sstevel@tonic-gate 					numResults, maxResults);
116*7c478bd9Sstevel@tonic-gate 	    if (!pcSrvTypes)
117*7c478bd9Sstevel@tonic-gate 		return (SLP_TRUE);
118*7c478bd9Sstevel@tonic-gate 	} else {
119*7c478bd9Sstevel@tonic-gate 	    /* async; invoke cb */
120*7c478bd9Sstevel@tonic-gate 	    cont = cb((SLPHandle) hp, pcSrvTypes, errCode, cookie);
121*7c478bd9Sstevel@tonic-gate 	}
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	/* cleanup */
124*7c478bd9Sstevel@tonic-gate 	free(pcSrvTypes);
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	/* check maxResults */
127*7c478bd9Sstevel@tonic-gate 	if (!hp->internal_call && *numResults == maxResults) {
128*7c478bd9Sstevel@tonic-gate 		return (SLP_FALSE);
129*7c478bd9Sstevel@tonic-gate 	}
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	return (cont);
132*7c478bd9Sstevel@tonic-gate }
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate static SLPError slp_packSrvTypeRqst(slp_handle_impl_t *hp, const char *na) {
135*7c478bd9Sstevel@tonic-gate 	SLPError err;
136*7c478bd9Sstevel@tonic-gate 	size_t len, nalen, msgLen, tmplen;
137*7c478bd9Sstevel@tonic-gate 	int all_nas;
138*7c478bd9Sstevel@tonic-gate 	slp_msg_t *msg = &(hp->msg);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	/*
141*7c478bd9Sstevel@tonic-gate 	 * Allocate iovec for the message. A SrvTypeRqst is layed out thus:
142*7c478bd9Sstevel@tonic-gate 	 *  0: header
143*7c478bd9Sstevel@tonic-gate 	 *  1: prlist length
144*7c478bd9Sstevel@tonic-gate 	 *  2: prlist (filled in later by networking code)
145*7c478bd9Sstevel@tonic-gate 	 *  3: na
146*7c478bd9Sstevel@tonic-gate 	 *  4: scopes length
147*7c478bd9Sstevel@tonic-gate 	 *  5: scopes (filled in later by networking code)
148*7c478bd9Sstevel@tonic-gate 	 */
149*7c478bd9Sstevel@tonic-gate 	if (!(msg->iov = calloc(6, sizeof (*(msg->iov))))) {
150*7c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "slp_packSrvTypeRqst", "out of memory");
151*7c478bd9Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
152*7c478bd9Sstevel@tonic-gate 	}
153*7c478bd9Sstevel@tonic-gate 	msg->iovlen = 6;
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	/* calculate msg length */
156*7c478bd9Sstevel@tonic-gate 	all_nas = strcmp(na, "*") == 0 ? 1 : 0;
157*7c478bd9Sstevel@tonic-gate 	if (all_nas) {
158*7c478bd9Sstevel@tonic-gate 		nalen = 0;
159*7c478bd9Sstevel@tonic-gate 	} else {
160*7c478bd9Sstevel@tonic-gate 		nalen = strlen(na);
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate 	nalen += 2;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	msgLen = 2 +	/* prlist length */
165*7c478bd9Sstevel@tonic-gate 	    nalen +	/* NA string */
166*7c478bd9Sstevel@tonic-gate 	    2;		/* Scope string length */
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	if (!(msg->msg = calloc(1, msgLen))) {
169*7c478bd9Sstevel@tonic-gate 		free(msg->iov);
170*7c478bd9Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "slp_packSrvTypeRqst", "out of memory");
171*7c478bd9Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	/* set pointer to PR list and scope list length spaces */
175*7c478bd9Sstevel@tonic-gate 	msg->prlistlen.iov_base = msg->msg;
176*7c478bd9Sstevel@tonic-gate 	msg->prlistlen.iov_len = 2;
177*7c478bd9Sstevel@tonic-gate 	msg->iov[1].iov_base = msg->msg;
178*7c478bd9Sstevel@tonic-gate 	msg->iov[1].iov_len = 2;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	msg->scopeslen.iov_base = msg->msg + 2;
181*7c478bd9Sstevel@tonic-gate 	msg->scopeslen.iov_len = 2;
182*7c478bd9Sstevel@tonic-gate 	msg->iov[4].iov_base = msg->msg + 2;
183*7c478bd9Sstevel@tonic-gate 	msg->iov[4].iov_len = 2;
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	/* set up the scopes and prlist pointers into iov */
186*7c478bd9Sstevel@tonic-gate 	msg->prlist = &(msg->iov[2]);
187*7c478bd9Sstevel@tonic-gate 	msg->scopes = &(msg->iov[5]);
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	len = 4;
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 	/* set up NA string in iovec */
192*7c478bd9Sstevel@tonic-gate 	msg->iov[3].iov_base = msg->msg + len;
193*7c478bd9Sstevel@tonic-gate 	tmplen = len;
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	if (all_nas) {
196*7c478bd9Sstevel@tonic-gate 		err = slp_add_sht(msg->msg, msgLen, 0xffff, &len);
197*7c478bd9Sstevel@tonic-gate 	} else {
198*7c478bd9Sstevel@tonic-gate 		err = slp_add_string(msg->msg, msgLen, na, &len);
199*7c478bd9Sstevel@tonic-gate 	}
200*7c478bd9Sstevel@tonic-gate 	msg->iov[3].iov_len = len - tmplen;
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	hp->fid = SRVTYPERQST;
203*7c478bd9Sstevel@tonic-gate 	if (err == SLP_OK) {
204*7c478bd9Sstevel@tonic-gate 		return (SLP_OK);
205*7c478bd9Sstevel@tonic-gate 	}
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	/* else error */
208*7c478bd9Sstevel@tonic-gate 	free(msg->iov);
209*7c478bd9Sstevel@tonic-gate 	free(msg->msg);
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	return (err);
212*7c478bd9Sstevel@tonic-gate }
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate /*
215*7c478bd9Sstevel@tonic-gate  * Using the collator, determines which types in the types list
216*7c478bd9Sstevel@tonic-gate  * have already been recieved, and composes a new list of the remaining
217*7c478bd9Sstevel@tonic-gate  * (unique) types. If there are no unique types, returns NULL;
218*7c478bd9Sstevel@tonic-gate  * types is destructively modified.
219*7c478bd9Sstevel@tonic-gate  */
220*7c478bd9Sstevel@tonic-gate static char *collate_types(char *types, void **collator,
221*7c478bd9Sstevel@tonic-gate 				int *numResults, int maxResults) {
222*7c478bd9Sstevel@tonic-gate 	char *p, *s, **res, *utypes = NULL;
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	/* walk through the types list */
225*7c478bd9Sstevel@tonic-gate 	p = types;
226*7c478bd9Sstevel@tonic-gate 	for (s = types; p && *numResults != maxResults; s = p) {
227*7c478bd9Sstevel@tonic-gate 		p = slp_utf_strchr(s, ',');
228*7c478bd9Sstevel@tonic-gate 		if (p)
229*7c478bd9Sstevel@tonic-gate 			*p++ = 0;
230*7c478bd9Sstevel@tonic-gate 		if (!(s = strdup(s))) {
231*7c478bd9Sstevel@tonic-gate 		    free(types);
232*7c478bd9Sstevel@tonic-gate 		    if (utypes) free(utypes);
233*7c478bd9Sstevel@tonic-gate 		    slp_err(LOG_CRIT, 0, "collate_types", "out of memory");
234*7c478bd9Sstevel@tonic-gate 		    return (NULL);
235*7c478bd9Sstevel@tonic-gate 		}
236*7c478bd9Sstevel@tonic-gate 		/* search the tree for this type */
237*7c478bd9Sstevel@tonic-gate 		res = slp_tsearch((void *) s, collator,
238*7c478bd9Sstevel@tonic-gate 			(int (*)(const void *, const void *)) slp_strcasecmp);
239*7c478bd9Sstevel@tonic-gate 		if (*res == s) {
240*7c478bd9Sstevel@tonic-gate 			/* first time we've encountered this type */
241*7c478bd9Sstevel@tonic-gate 			slp_add2list(s, &utypes, SLP_FALSE);
242*7c478bd9Sstevel@tonic-gate 			(*numResults)++;
243*7c478bd9Sstevel@tonic-gate 		} else {
244*7c478bd9Sstevel@tonic-gate 			/* else  already in tree */
245*7c478bd9Sstevel@tonic-gate 			free(s);
246*7c478bd9Sstevel@tonic-gate 		}
247*7c478bd9Sstevel@tonic-gate 	}
248*7c478bd9Sstevel@tonic-gate 	free(types);
249*7c478bd9Sstevel@tonic-gate 	return (utypes);
250*7c478bd9Sstevel@tonic-gate }
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate /*
253*7c478bd9Sstevel@tonic-gate  * This is used after all types have been collated into the tree.
254*7c478bd9Sstevel@tonic-gate  * It walks through the tree, composing a list from all the types in
255*7c478bd9Sstevel@tonic-gate  * the tree, and freeing each node of the tree as it goes.
256*7c478bd9Sstevel@tonic-gate  * Returns the list, or NULL if the tree is empty.
257*7c478bd9Sstevel@tonic-gate  */
258*7c478bd9Sstevel@tonic-gate /* the walk action function: */
259*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
260*7c478bd9Sstevel@tonic-gate static void collect_types(void *node, VISIT order, int level, void *cookie) {
261*7c478bd9Sstevel@tonic-gate 	char **types = (char **)cookie;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (order == endorder || order == leaf) {
264*7c478bd9Sstevel@tonic-gate 		char *t = *(char **)node;
265*7c478bd9Sstevel@tonic-gate 		slp_add2list(t, types, SLP_FALSE);
266*7c478bd9Sstevel@tonic-gate 		free(t);
267*7c478bd9Sstevel@tonic-gate 		free(node);
268*7c478bd9Sstevel@tonic-gate 	}
269*7c478bd9Sstevel@tonic-gate }
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate /* the walk driver: */
272*7c478bd9Sstevel@tonic-gate static char *build_types_list(void *collator) {
273*7c478bd9Sstevel@tonic-gate 	char *types = NULL;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	if (!collator)
276*7c478bd9Sstevel@tonic-gate 		return (NULL);
277*7c478bd9Sstevel@tonic-gate 	slp_twalk(collator, collect_types, 0, (void *) &types);
278*7c478bd9Sstevel@tonic-gate 	return (types);
279*7c478bd9Sstevel@tonic-gate }
280