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"
30 * Public utilities and convenience calls (from the API spec):
31 * SLPFindScopes (queries for all known scopes)
32 * SLPEscape / Unescape
44 #include <slp-internal.h>
51 typedef SLPBoolean
SLPScopeCallback(SLPHandle
, const char *, SLPError
, void *);
53 static SLPSrvURLCallback collate_scopes
;
54 static void collect_scopes(void *, VISIT
, int, void *);
55 static SLPBoolean
unpackSAAdvert_scope(slp_handle_impl_t
*, char *,
56 SLPScopeCallback
, void *,
58 static SLPError
SAAdvert_for_scopes(SLPHandle
, void **);
59 static SLPError
slp_unescape(const char *, char **, SLPBoolean
, const char);
62 * Finds scopes according the the user administrative model.
64 SLPError
SLPFindScopes(SLPHandle hSLP
, char **ppcScopes
) {
66 char *reply
, *unesc_reply
;
68 void *collator
= NULL
;
70 if (!hSLP
|| !ppcScopes
) {
71 return (SLP_PARAMETER_BAD
);
74 /* first try administratively configured scopes */
75 if ((err
= slp_administrative_scopes(ppcScopes
, SLP_FALSE
))
85 /* DAs from active and passive discovery */
86 if ((err
= slp_find_das("", &reply
)) != SLP_OK
&&
87 err
!= SLP_NETWORK_ERROR
)
90 /* Unpack the reply */
92 int numResults
= 0; /* placeholder; not actually used */
94 /* tag call as internal */
95 ((slp_handle_impl_t
*)hSLP
)->internal_call
= SLP_TRUE
;
97 (void) slp_unpackSrvReply(
98 hSLP
, reply
, collate_scopes
,
99 &stree
, &collator
, &numResults
);
100 /* invoke last call */
101 (void) slp_unpackSrvReply(
102 hSLP
, NULL
, collate_scopes
,
103 &stree
, &collator
, &numResults
);
106 /* revert internal call tag */
107 ((slp_handle_impl_t
*)hSLP
)->internal_call
= SLP_FALSE
;
110 /* Finally, if no results yet, try SA discovery */
112 (void) SAAdvert_for_scopes(hSLP
, &stree
);
116 /* found none, so just return "default" */
117 if (!(*ppcScopes
= strdup("default"))) {
118 slp_err(LOG_CRIT
, 0, "SLPFindScopes", "out of memory");
119 return (SLP_MEMORY_ALLOC_FAILED
);
124 /* we now have a btree, each leaf of which is a unique scope */
125 slp_twalk(stree
, collect_scopes
, 0, (void *) ppcScopes
);
127 /* unescape scopes list */
128 if ((err
= slp_unescape(*ppcScopes
, &unesc_reply
, SLP_FALSE
, '%'))
131 *ppcScopes
= unesc_reply
;
140 * Finds scopes according to the adminstrative scoping model. A
141 * comma-seperated list of scopes is returned in *ppcScopes; the
142 * caller must free *ppcScopes.
143 * If the return_default parameter is true, and no scopes are found,
144 * *ppcScopes will be set to 'default', otherwise, *ppcScopes will
145 * be NULL. This helps simplify internal memory management.
147 SLPError
slp_administrative_scopes(char **ppcScopes
,
148 SLPBoolean return_default
) {
149 const char *useScopes
;
153 /* @@@ first try DHCP */
154 /* next try the useScopes property */
155 useScopes
= SLPGetProperty(SLP_CONFIG_USESCOPES
);
157 if (useScopes
&& *useScopes
) {
158 if (!(*ppcScopes
= strdup(useScopes
))) {
159 slp_err(LOG_CRIT
, 0, "SLPFindScopes", "out of memory");
160 return (SLP_MEMORY_ALLOC_FAILED
);
165 /* found none, so just return "default" */
166 if (return_default
&& !(*ppcScopes
= strdup("default"))) {
167 slp_err(LOG_CRIT
, 0, "SLPFindScopes", "out of memory");
168 return (SLP_MEMORY_ALLOC_FAILED
);
174 * This function operates on the same btree as the collate_scopes().
175 * The difference is that this one is called for each
179 static SLPBoolean
saadvert_callback(SLPHandle hp
, char *scopes
,
180 SLPError err
, void **stree
) {
188 s
= strtok_r((char *)scopes
, ",", &tstate
);
190 s
= strtok_r(NULL
, ",", &tstate
)) {
192 char *ascope
, **srch
;
194 if (!(ascope
= strdup(s
))) { /* no memory! */
195 slp_err(LOG_CRIT
, 0, "collate_scopes",
201 (void *) ascope
, stree
,
202 (int (*)(const void *, const void *)) slp_strcasecmp
);
204 /* scope is already in there, so just free ascope */
212 * Generates an SAAdvert solicitation, and returns any scopes found
213 * from all recieved SAAdverts in stree. stree must be a btree
216 static SLPError
SAAdvert_for_scopes(SLPHandle hSLP
, void **stree
) {
218 SLPBoolean sync_state
;
219 slp_handle_impl_t
*hp
= (slp_handle_impl_t
*)hSLP
;
221 const char *type_hint
;
223 /* get type hint, if set */
224 if ((type_hint
= SLPGetProperty(SLP_CONFIG_TYPEHINT
)) != NULL
&&
227 size_t hintlen
= strlen(type_hint
);
228 size_t predlen
= strlen("(service-type=)");
231 if (hintlen
> (SLP_MAX_STRINGLEN
- predlen
)) {
232 return (SLP_PARAMETER_BAD
);
234 if (!(predicate
= malloc(hintlen
+ predlen
+ 1))) {
235 slp_err(LOG_CRIT
, 0, "SAAdvert_for_scopes",
237 return (SLP_MEMORY_ALLOC_FAILED
);
239 (void) strcpy(predicate
, "(service-type=");
240 (void) strcat(predicate
, type_hint
);
241 (void) strcat(predicate
, ")");
247 /* No callback for SLPFindScopes, so force synchronous mode only */
248 sync_state
= hp
->async
;
249 hp
->async
= SLP_FALSE
;
251 if ((err
= slp_start_call(hp
)) != SLP_OK
)
254 err
= slp_packSrvRqst("service:service-agent", predicate
, hp
);
257 err
= slp_ua_common(hSLP
, "",
258 (SLPGenericAppCB
*)saadvert_callback
,
260 (SLPMsgReplyCB
*)unpackSAAdvert_scope
);
269 /* restore sync state */
270 hp
->async
= sync_state
;
276 * Unpack an SAAdvert and pass each set of scopes into cb.
279 static SLPBoolean
unpackSAAdvert_scope(slp_handle_impl_t
*hSLP
, char *reply
,
280 SLPScopeCallback cb
, void *cookie
,
281 void **collator
, int *numResults
) {
282 char *surl
, *scopes
, *attrs
;
286 cb(hSLP
, NULL
, SLP_LAST_CALL
, cookie
);
290 /* tag call as internal; gets all scopes, regardless of maxResults */
291 hSLP
->internal_call
= SLP_TRUE
;
293 if (slp_unpackSAAdvert(reply
, &surl
, &scopes
, &attrs
) != SLP_OK
) {
297 cont
= cb(hSLP
, scopes
, SLP_OK
, cookie
);
299 /* revert internal_call tag */
300 hSLP
->internal_call
= SLP_FALSE
;
310 * Creates a service request for finding DAs or SAs (based on 'filter'),
311 * and sends it to slpd, returning the reply in 'reply'.
313 SLPError
slp_find_das(const char *filter
, char **reply
) {
315 char *msg
, hostname
[MAXHOSTNAMELEN
];
317 /* Try the cache first */
318 if (*reply
= slp_find_das_cached(filter
)) {
323 * create a find scopes message:
324 * this is a SrvRqst for the type directory-agent.sun.
326 /* use the local host's name for the scope */
327 (void) gethostname(hostname
, MAXHOSTNAMELEN
);
329 err
= slp_packSrvRqst_single(
330 SLP_SUN_DA_TYPE
, hostname
, filter
, &msg
, "en");
333 err
= slp_send2slpd(msg
, reply
);
337 /* Add the reply to the cache */
339 slp_put_das_cached(filter
, *reply
, slp_get_length(*reply
));
346 * This is called for each URL entry in the DA service reply (sun private).
347 * Contained within the cookie is a btree, to which it adds new
348 * scopes from the URL entry. The scopes are retrieved from the btree
349 * by traversing the tree in SLPFindScopes().
350 * SLPHandle h is NULL, so don't touch it!
353 static SLPBoolean
collate_scopes(SLPHandle h
, const char *u
,
354 unsigned short lifetime
,
355 SLPError errCode
, void *cookie
) {
357 char *s
, *tstate
, *p
, *url
;
358 void **collator
= cookie
;
360 if (errCode
!= SLP_OK
)
363 /* dup url so as not to corrupt da cache */
364 if (!(url
= strdup(u
))) {
365 slp_err(LOG_CRIT
, 0, "collate_scopes", "out of memory");
369 /* parse url into a SLPSrvURL struct */
370 if (SLPParseSrvURL(url
, &surl
) != SLP_OK
)
371 return (SLP_TRUE
); /* bad URL; skip it */
373 /* collate the scopes using the btree stree->scopes: */
374 /* skip the 'scopes=' part */
375 if (!(p
= strchr(surl
->s_pcSrvPart
, '='))) {
377 return (SLP_TRUE
); /* bad URL; skip it */
382 s
= strtok_r(p
, ",", &tstate
);
384 s
= strtok_r(NULL
, ",", &tstate
)) {
386 char *ascope
, **srch
;
388 if (!(ascope
= strdup(s
))) { /* no memory! */
389 slp_err(LOG_CRIT
, 0, "collate_scopes",
396 (void *) ascope
, collator
,
397 (int (*)(const void *, const void *)) slp_strcasecmp
);
399 /* scope is already in there, so just free ascope */
410 * Each time we visit a node for the last time, copy that scope into
411 * the scope collection and free the scope string and the node.
414 static void collect_scopes(void *node
, VISIT order
, int level
, void *cookie
) {
415 char **scopes
= (char **)cookie
;
417 if (order
== endorder
|| order
== leaf
) {
418 char *s
= *(char **)node
;
419 slp_add2list(s
, scopes
, SLP_FALSE
);
425 void SLPFree(void *pvMem
) {
434 #define isBadTagChar(c) ((c) == '*' || (c) == '_' || \
435 (c) == '\n' || (c) == '\t' || (c) == '\r')
437 #define isReserved(c) ((c) <= 31 || (c) == '(' || (c) == ')' || \
438 (c) == ',' || (c) == '\\' || (c) == '!' || \
439 (c) == '<' || (c) == '=' || (c) == '>' || \
442 SLPError
SLPEscape(const char *pcInbuf
, char **ppcOutBuf
, SLPBoolean isTag
) {
443 char *buf
, *pin
, *pout
;
445 if (!pcInbuf
|| !ppcOutBuf
)
446 return (SLP_PARAMETER_BAD
);
448 if (!(buf
= malloc(strlen(pcInbuf
) * 3 + 1))) {
449 slp_err(LOG_CRIT
, 0, "SLPEscape", "out of memory");
450 return (SLP_MEMORY_ALLOC_FAILED
);
454 for (pin
= (char *)pcInbuf
, pout
= buf
; *pin
; ) {
457 /* If char is start of multibyte char, just copy it in */
458 if ((len
= mblen(pin
, MB_CUR_MAX
)) > 1) {
460 for (i
= 0; i
< len
&& *pin
; i
++)
465 /* check for bad tag */
466 if (isTag
&& isBadTagChar(*pin
))
467 return (SLP_PARSE_ERROR
);
469 if (isReserved(*pin
)) {
471 return (SLP_PARSE_ERROR
);
472 (void) sprintf(pout
, "\\%.2x", *pin
);
484 SLPError
SLPUnescape(const char *pcInbuf
, char **ppcOutBuf
, SLPBoolean isTag
) {
485 if (!pcInbuf
|| !ppcOutBuf
)
486 return (SLP_PARAMETER_BAD
);
488 return (slp_unescape(pcInbuf
, ppcOutBuf
, isTag
, '\\'));
493 * The actual unescaping routine; allows for different escape chars.
495 static SLPError
slp_unescape(const char *pcInbuf
, char **ppcOutBuf
,
496 SLPBoolean isTag
, const char esc_char
) {
497 char *buf
, *pin
, *pout
, conv
[3];
499 if (!(buf
= malloc(strlen(pcInbuf
) * 3 + 1))) {
500 slp_err(LOG_CRIT
, 0, "SLPEscape", "out of memory");
501 return (SLP_MEMORY_ALLOC_FAILED
);
506 for (pin
= (char *)pcInbuf
, pout
= buf
; *pin
; ) {
509 /* If char is start of multibyte char, just copy it in */
510 if ((len
= mblen(pin
, MB_CUR_MAX
)) > 1) {
512 for (i
= 0; i
< len
&& *pin
; i
++)
517 if (*pin
== esc_char
) {
518 if (!pin
[1] || !pin
[2])
519 return (SLP_PARSE_ERROR
);
523 *pout
++ = (char)strtol(conv
, NULL
, 16);
524 if (isTag
&& isBadTagChar(*pout
))
525 return (SLP_PARSE_ERROR
);
538 * All properties are stored in a global tree (prop_table). This
539 * tree is created and accessed by slp_tsearch and slp_tfind.
542 const char *key
, *val
;
544 typedef struct prop_entry slp_prop_entry_t
;
546 /* Global properties table */
547 static void *slp_props
= NULL
;
548 static mutex_t prop_table_lock
= DEFAULTMUTEX
;
550 static void setDefaults();
552 static int compare_props(const void *a
, const void *b
) {
554 ((slp_prop_entry_t
*)a
)->key
,
555 ((slp_prop_entry_t
*)b
)->key
));
558 void SLPSetProperty(const char *pcName
, const char *pcValue
) {
559 slp_prop_entry_t
*pe
, **pe2
;
561 if (!slp_props
) setDefaults();
563 if (!pcName
|| !pcValue
) {
567 if (!(pe
= malloc(sizeof (*pe
)))) {
568 slp_err(LOG_CRIT
, 0, "SLPSetProperty", "out of memory");
572 /* place the strings under library ownership */
573 if (!(pe
->key
= strdup(pcName
))) {
575 slp_err(LOG_CRIT
, 0, "SLPSetProperty", "out of memory");
579 if (!(pe
->val
= strdup(pcValue
))) {
580 free((void *) pe
->key
);
582 slp_err(LOG_CRIT
, 0, "SLPSetProperty", "out of memory");
586 /* is pcName already set? */
587 (void) mutex_lock(&prop_table_lock
);
588 pe2
= slp_tsearch((void *) pe
, &slp_props
, compare_props
);
590 /* this prop is already set; overwrite the old value */
591 free((void *) (*pe2
)->val
);
592 (*pe2
)->val
= pe
->val
;
593 free((void *) pe
->key
);
596 (void) mutex_unlock(&prop_table_lock
);
599 const char *SLPGetProperty(const char *pcName
) {
600 slp_prop_entry_t pe
[1], **ans
;
602 if (!slp_props
) setDefaults();
610 (void) mutex_lock(&prop_table_lock
);
611 ans
= slp_tfind(pe
, &slp_props
, compare_props
);
612 (void) mutex_unlock(&prop_table_lock
);
614 return ((*ans
)->val
);
618 static void setDefaults() {
619 slp_prop_entry_t
*pe
;
620 static mutex_t lock
= DEFAULTMUTEX
;
622 (void) mutex_lock(&lock
);
624 (void) mutex_unlock(&lock
);
628 pe
= malloc(sizeof (*pe
));
629 pe
->key
= strdup(SLP_CONFIG_ISBROADCASTONLY
);
630 pe
->val
= strdup("false");
631 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
633 pe
= malloc(sizeof (*pe
));
634 pe
->key
= strdup(SLP_CONFIG_MULTICASTTTL
);
635 pe
->val
= strdup("255");
636 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
638 pe
= malloc(sizeof (*pe
));
639 pe
->key
= strdup(SLP_CONFIG_MULTICASTMAXWAIT
);
640 pe
->val
= strdup("15000");
641 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
643 pe
= malloc(sizeof (*pe
));
644 pe
->key
= strdup(SLP_CONFIG_DATAGRAMTIMEOUTS
);
645 pe
->val
= strdup("2000,2000,2000");
646 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
648 pe
= malloc(sizeof (*pe
));
649 pe
->key
= strdup(SLP_CONFIG_MULTICASTTIMEOUTS
);
650 pe
->val
= strdup("1000,3000,3000,3000,3000");
651 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
653 pe
= malloc(sizeof (*pe
));
654 pe
->key
= SLP_CONFIG_MTU
; pe
->val
= "1400";
655 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
657 pe
= malloc(sizeof (*pe
));
658 pe
->key
= strdup(SLP_CONFIG_MAXRESULTS
);
659 pe
->val
= strdup("-1");
660 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
662 pe
= malloc(sizeof (*pe
));
663 pe
->key
= strdup(SLP_CONFIG_SECURITY_ON
);
664 pe
->val
= strdup("false");
665 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
667 pe
= malloc(sizeof (*pe
));
668 pe
->key
= strdup(SLP_CONFIG_BYPASS_AUTH
);
669 pe
->val
= strdup("false");
670 (void) slp_tsearch((void *) pe
, &slp_props
, compare_props
);
674 (void) mutex_unlock(&lock
);
677 static const char *error_strings
[] = {
679 "Language not supported", /* -1 */
680 "Parse error", /* -2 */
681 "Invalid registration", /* -3 */
682 "Scope not supported", /* -4 */
683 "Invalid error number", /* -5 */
684 "Authentication absent", /* -6 */
685 "Authentication failed", /* -7 */
686 "Invalid error number", /* -8 */
687 "Invalid error number", /* -9 */
688 "Invalid error number", /* -10 */
689 "Invalid error number", /* -11 */
690 "Invalid error number", /* -12 */
691 "Invalid update", /* -13 */
692 "Invalid error number", /* -14 */
693 "Invalid error number", /* -15 */
694 "Invalid error number", /* -16 */
695 "Not implemented", /* -17 */
696 "Buffer overflow", /* -18 */
697 "Network timed out", /* -19 */
698 "Network init failed", /* -20 */
699 "Memory alloc failed", /* -21 */
700 "Parameter bad", /* -22 */
701 "Network error", /* -23 */
702 "Internal system error", /* -24 */
703 "Handle in use", /* -25 */
704 "Type error" /* -26 */
707 #define SLP_MAX_ERR_CNT 26
709 const char *slp_strerror(SLPError err
) {
713 if (err
== SLP_LAST_CALL
) {
715 } else if (err
== SLP_SECURITY_UNAVAILABLE
) {
716 str
= "Security Implementation Unavailable";
719 if (abserr
> SLP_MAX_ERR_CNT
) {
720 str
= "Invalid error number";
722 str
= error_strings
[abserr
];
726 return (dgettext("libslp", str
));