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