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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <slp-internal.h>
36 unsigned short lifetime
;
39 struct caller_bundle
{
40 SLPSrvURLCallback
*cb
;
45 static int compare_surls(struct surl_node
*, struct surl_node
*);
46 static char *collate_surls(char *, unsigned short, void **);
47 static void traverse_surls(SLPHandle
, SLPSrvURLCallback
, void *, void *);
48 static void process_surl_node(void *, VISIT
, int, void *);
49 static SLPBoolean
unpackDAAdvert_srv(slp_handle_impl_t
*, char *,
50 SLPSrvURLCallback
, void *,
52 static SLPBoolean
unpackSAAdvert_srv(slp_handle_impl_t
*, char *,
53 SLPSrvURLCallback
, void *,
56 SLPError
SLPFindSrvs(SLPHandle hSLP
, const char *pcServiceType
,
57 const char *pcScope
, const char *pcSearchFilter
,
58 SLPSrvURLCallback callback
, void *pvUser
) {
60 slp_handle_impl_t
*hp
= (slp_handle_impl_t
*)hSLP
;
62 strcasecmp(pcServiceType
, "service:service-agent") == 0;
64 strcasecmp(pcServiceType
, "service:directory-agent") == 0;
65 int isSpecial
= wantSAAdvert
|| wantDAAdvert
;
66 SLPMsgReplyCB
*unpack_cb
;
68 if (!hSLP
|| !pcServiceType
|| !pcScope
|| (!*pcScope
&& !isSpecial
) ||
69 !pcSearchFilter
|| !callback
) {
70 return (SLP_PARAMETER_BAD
);
73 if ((strlen(pcServiceType
) > SLP_MAX_STRINGLEN
) ||
74 (strlen(pcScope
) > SLP_MAX_STRINGLEN
) ||
75 (strlen(pcSearchFilter
) > SLP_MAX_STRINGLEN
)) {
76 return (SLP_PARAMETER_BAD
);
79 if ((err
= slp_start_call(hSLP
)) != SLP_OK
)
82 /* Special unpacker for DA and SA solicitations */
84 unpack_cb
= (SLPMsgReplyCB
*)unpackDAAdvert_srv
;
85 hp
->force_multicast
= SLP_TRUE
;
86 } else if (wantSAAdvert
) {
87 unpack_cb
= (SLPMsgReplyCB
*)unpackSAAdvert_srv
;
88 hp
->force_multicast
= SLP_TRUE
;
90 /* normal service request */
91 unpack_cb
= (SLPMsgReplyCB
*)slp_unpackSrvReply
;
94 err
= slp_packSrvRqst(pcServiceType
, pcSearchFilter
, hp
);
97 err
= slp_ua_common(hSLP
, pcScope
,
98 (SLPGenericAppCB
*) callback
, pvUser
,
106 SLPBoolean
slp_unpackSrvReply(slp_handle_impl_t
*hp
, char *reply
,
107 SLPSrvURLCallback cb
, void *cookie
,
108 void **collator
, int *numResults
) {
110 unsigned short urlCount
, protoErrCode
;
113 int maxResults
= slp_get_maxResults();
114 SLPBoolean cont
= SLP_TRUE
;
117 /* no more results */
118 /* traverse_surls:invoke cb for sync case,and free resources */
120 traverse_surls(hp
, cb
, cookie
, *collator
);
122 cb(hp
, NULL
, 0, SLP_LAST_CALL
, cookie
);
126 len
= slp_get_length(reply
);
127 off
= SLP_HDRLEN
+ slp_get_langlen(reply
);
129 if (slp_get_sht(reply
, len
, &off
, &protoErrCode
) != SLP_OK
)
131 /* internal errors should have been filtered out by the net code */
132 if ((errCode
= slp_map_err(protoErrCode
)) != SLP_OK
) {
133 return (cb(hp
, NULL
, 0, errCode
, cookie
));
136 /* url entry count */
137 if (slp_get_sht(reply
, len
, &off
, &urlCount
) != SLP_OK
)
140 /* for each srvRply, unpack and pass to CB */
141 for (i
= 0; i
< urlCount
&& !hp
->cancel
; i
++) {
143 unsigned short sLifetime
;
148 /* parse URL entry into params */
149 off
++; /* skip reserved byte */
151 if (slp_get_sht(reply
, len
, &off
, &sLifetime
) != SLP_OK
)
153 /* URL itself; keep track of it in case we need to verify */
154 url_tbv
= reply
+ off
;
156 if (slp_get_string(reply
, len
, &off
, &pcSrvURL
) != SLP_OK
)
158 tbv_len
= off
- tbv_len
;
160 /* number of url auths */
161 if (slp_get_byte(reply
, len
, &off
, &nURLAuthBlocks
) != SLP_OK
)
164 /* get and verify auth blocks */
165 if ((!hp
->internal_call
&& slp_get_security_on()) ||
166 nURLAuthBlocks
> 0) {
170 iov
[0].iov_base
= url_tbv
;
171 iov
[0].iov_len
= tbv_len
;
173 if (slp_verify(iov
, 1,
183 /* collate the srv urls for sync behavior */
185 pcSrvURL
= collate_surls(pcSrvURL
, sLifetime
, collator
);
205 /* check maxResults */
206 if (!hp
->internal_call
&& *numResults
== maxResults
) {
217 * unpackDAAdvert_srv follows the same same logic flow as slp_unpackSrvReply
218 * with two differences: the message in reply is a DAAdvert, and
219 * this function is not used internally, so hp is never NULL. Although
220 * all info from a DAAdvert is returned by slp_unpackDAAdvert, here
221 * the recipient (the user-supplied SLPSrvURLCallback) is interested
222 * only in the DA service URL.
224 static SLPBoolean
unpackDAAdvert_srv(slp_handle_impl_t
*hp
, char *reply
,
225 SLPSrvURLCallback cb
, void *cookie
,
226 void **collator
, int *numResults
) {
227 char *surl
, *scopes
, *attrs
, *spis
;
228 SLPBoolean cont
= SLP_TRUE
;
230 int maxResults
= slp_get_maxResults();
233 /* no more results */
234 /* traverse_surls:invoke cb for sync case,and free resources */
236 traverse_surls(hp
, cb
, cookie
, *collator
);
238 cb(hp
, NULL
, 0, SLP_LAST_CALL
, cookie
);
242 if (slp_unpackDAAdvert(reply
, &surl
, &scopes
, &attrs
, &spis
, &errCode
)
246 if (errCode
!= SLP_OK
) {
247 return (cb(hp
, NULL
, 0, errCode
, cookie
));
250 /* collate the urls */
251 surl
= collate_surls(surl
, 0, collator
);
258 cont
= cb((SLPHandle
)hp
, surl
, 0, errCode
, cookie
);
267 /* check maxResults */
268 if (!hp
->internal_call
&& *numResults
== maxResults
) {
275 * unpackSAAdvert_srv follows the same same logic flow as slp_unpackSrvReply
276 * with two differences: the message in reply is a SAAdvert, and
277 * this function is not used internally, so hp is never NULL. Although
278 * all info from an SAAdvert is returned by slp_unpackSAAdvert, here
279 * the recipient (the user-supplied SLPSrvURLCallback) is interested
280 * only in the SA service URL.
282 static SLPBoolean
unpackSAAdvert_srv(slp_handle_impl_t
*hp
, char *reply
,
283 SLPSrvURLCallback cb
, void *cookie
,
284 void **collator
, int *numResults
) {
285 char *surl
, *scopes
, *attrs
;
286 SLPBoolean cont
= SLP_TRUE
;
287 int maxResults
= slp_get_maxResults();
290 /* no more results */
291 /* traverse_surls:invoke cb for sync case,and free resources */
294 traverse_surls(hp
, cb
, cookie
, *collator
);
296 cb(hp
, NULL
, 0, SLP_LAST_CALL
, cookie
);
300 if (slp_unpackSAAdvert(reply
, &surl
, &scopes
, &attrs
) != SLP_OK
) {
304 /* collate the urls */
305 surl
= collate_surls(surl
, 0, collator
);
312 cont
= cb((SLPHandle
)hp
, surl
, 0, SLP_OK
, cookie
);
320 /* check maxResults */
321 if (!hp
->internal_call
&& *numResults
== maxResults
) {
328 SLPError
slp_packSrvRqst(const char *type
,
330 slp_handle_impl_t
*hp
) {
332 size_t len
, msgLen
, tmplen
;
333 slp_msg_t
*msg
= &(hp
->msg
);
336 if (slp_get_security_on()) {
337 spi
= (char *)SLPGetProperty(SLP_CONFIG_SPI
);
345 * Allocate iovec for the messge. A SrvRqst is layed out thus:
348 * 2: prlist (filled in later by networking code)
349 * 3: service type string
351 * 5: scopes (filled in later by networking code)
352 * 6: predicate string and SPI string
354 if (!(msg
->iov
= calloc(7, sizeof (*(msg
->iov
))))) {
355 slp_err(LOG_CRIT
, 0, "slp_packSrvRqst", "out of memory");
356 return (SLP_MEMORY_ALLOC_FAILED
);
360 /* calculate msg length */
361 msgLen
= 2 + /* prlist length */
362 2 + strlen(type
) + /* service type */
363 2 + /* scope list length */
364 2 + strlen(filter
) + /* predicate string */
365 2 + strlen(spi
); /* SPI string */
367 if (!(msg
->msg
= calloc(1, msgLen
))) {
369 slp_err(LOG_CRIT
, 0, "slp_packSrvRqst", "out of memory");
370 return (SLP_MEMORY_ALLOC_FAILED
);
373 /* set pointer to PR list and scope list length spaces */
374 msg
->prlistlen
.iov_base
= msg
->msg
;
375 msg
->prlistlen
.iov_len
= 2;
376 msg
->iov
[1].iov_base
= msg
->msg
;
377 msg
->iov
[1].iov_len
= 2;
379 msg
->scopeslen
.iov_base
= msg
->msg
+ 2;
380 msg
->scopeslen
.iov_len
= 2;
381 msg
->iov
[4].iov_base
= msg
->msg
+ 2;
382 msg
->iov
[4].iov_len
= 2;
384 /* set up the scopes and prlist pointers into iov */
385 msg
->prlist
= &(msg
->iov
[2]);
386 msg
->scopes
= &(msg
->iov
[5]);
390 /* Add type string */
391 msg
->iov
[3].iov_base
= msg
->msg
+ len
;
394 err
= slp_add_string(msg
->msg
, msgLen
, type
, &len
);
395 msg
->iov
[3].iov_len
= len
- tmplen
;
400 /* Add search filter */
401 msg
->iov
[6].iov_base
= msg
->msg
+ len
;
404 err
= slp_add_string(msg
->msg
, msgLen
, filter
, &len
);
408 err
= slp_add_string(msg
->msg
, msgLen
, spi
, &len
);
410 msg
->iov
[6].iov_len
= len
- tmplen
;
427 * Caller must free msg
429 SLPError
slp_packSrvRqst_single(const char *type
,
438 SLP_HDRLEN
+ strlen(lang
) + 2 +
442 2; /* No SPI string for internal calls */
444 if (!(*msg
= calloc(msgLen
, 1))) {
445 slp_err(LOG_CRIT
, 0, "slp_packSrvRqst_single",
447 return (SLP_MEMORY_ALLOC_FAILED
);
451 err
= slp_add_header(lang
, *msg
, msgLen
, SRVRQST
, msgLen
, &len
);
453 len
+= 2; /* empty PR list */
456 err
= slp_add_string(*msg
, msgLen
, type
, &len
);
458 err
= slp_add_string(*msg
, msgLen
, scopes
, &len
);
460 err
= slp_add_string(*msg
, msgLen
, filter
, &len
);
462 /* empty SPI string */
463 err
= slp_add_string(*msg
, msgLen
, "", &len
);
469 static int compare_surls(struct surl_node
*s1
, struct surl_node
*s2
) {
470 if (s1
->lifetime
!= s2
->lifetime
)
471 return (s1
->lifetime
- s2
->lifetime
);
472 return (slp_strcasecmp(s1
->surl
, s2
->surl
));
476 * Using the collator, determine if this URL has already been processed.
477 * If so, free surl and return NULL, else return the URL.
479 static char *collate_surls(char *surl
, unsigned short life
, void **collator
) {
480 struct surl_node
*n
, **res
;
482 if (!(n
= malloc(sizeof (*n
)))) {
483 slp_err(LOG_CRIT
, 0, "collate_surls", "out of memory");
486 if (!(n
->surl
= strdup(surl
))) {
488 slp_err(LOG_CRIT
, 0, "collate_surls", "out of memory");
492 res
= slp_tsearch((void *) n
, collator
,
493 (int (*)(const void *, const void *)) compare_surls
);
495 /* first time we've encountered this url */
498 /* else already in tree */
505 static void traverse_surls(SLPHandle h
, SLPSrvURLCallback cb
,
506 void *cookie
, void *collator
) {
507 struct caller_bundle caller
[1];
512 caller
->cookie
= cookie
;
514 slp_twalk(collator
, process_surl_node
, 0, caller
);
518 static void process_surl_node(void *node
, VISIT order
, int level
, void *c
) {
520 SLPSrvURLCallback
*cb
;
521 slp_handle_impl_t
*h
;
522 struct caller_bundle
*caller
= (struct caller_bundle
*)c
;
524 if (order
== endorder
|| order
== leaf
) {
525 SLPBoolean cont
= SLP_TRUE
;
528 h
= (slp_handle_impl_t
*)caller
->handle
;
529 n
= *(struct surl_node
**)node
;
531 if (cont
&& (!h
|| !h
->async
))