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