2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Public utilities and convenience calls (from the API spec):
2N/A * SLPFindScopes (queries for all known scopes)
2N/A * SLPEscape / Unescape
2N/A * SLPFree
2N/A * SLPSet/GetProperty
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <syslog.h>
2N/A#include <netdb.h>
2N/A#include <unistd.h>
2N/A#include <libintl.h>
2N/A#include <slp-internal.h>
2N/A
2N/Astruct scopes_tree {
2N/A void *scopes;
2N/A int len;
2N/A};
2N/A
2N/Atypedef SLPBoolean SLPScopeCallback(SLPHandle, const char *, SLPError, void *);
2N/A
2N/Astatic SLPSrvURLCallback collate_scopes;
2N/Astatic void collect_scopes(void *, VISIT, int, void *);
2N/Astatic SLPBoolean unpackSAAdvert_scope(slp_handle_impl_t *, char *,
2N/A SLPScopeCallback, void *,
2N/A void **, int *);
2N/Astatic SLPError SAAdvert_for_scopes(SLPHandle, void **);
2N/Astatic SLPError slp_unescape(const char *, char **, SLPBoolean, const char);
2N/A
2N/A/*
2N/A * Finds scopes according the the user administrative model.
2N/A */
2N/ASLPError SLPFindScopes(SLPHandle hSLP, char **ppcScopes) {
2N/A SLPError err;
2N/A char *reply, *unesc_reply;
2N/A void *stree = NULL;
2N/A void *collator = NULL;
2N/A
2N/A if (!hSLP || !ppcScopes) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A /* first try administratively configured scopes */
2N/A if ((err = slp_administrative_scopes(ppcScopes, SLP_FALSE))
2N/A != SLP_OK) {
2N/A return (err);
2N/A }
2N/A
2N/A if (*ppcScopes) {
2N/A /* got scopes */
2N/A return (SLP_OK);
2N/A }
2N/A
2N/A /* DAs from active and passive discovery */
2N/A if ((err = slp_find_das("", &reply)) != SLP_OK &&
2N/A err != SLP_NETWORK_ERROR)
2N/A return (err);
2N/A
2N/A /* Unpack the reply */
2N/A if (reply) {
2N/A int numResults = 0; /* placeholder; not actually used */
2N/A
2N/A /* tag call as internal */
2N/A ((slp_handle_impl_t *)hSLP)->internal_call = SLP_TRUE;
2N/A
2N/A (void) slp_unpackSrvReply(
2N/A hSLP, reply, collate_scopes,
2N/A &stree, &collator, &numResults);
2N/A /* invoke last call */
2N/A (void) slp_unpackSrvReply(
2N/A hSLP, NULL, collate_scopes,
2N/A &stree, &collator, &numResults);
2N/A free(reply);
2N/A
2N/A /* revert internal call tag */
2N/A ((slp_handle_impl_t *)hSLP)->internal_call = SLP_FALSE;
2N/A }
2N/A
2N/A /* Finally, if no results yet, try SA discovery */
2N/A if (!stree) {
2N/A (void) SAAdvert_for_scopes(hSLP, &stree);
2N/A }
2N/A
2N/A if (!stree) {
2N/A /* found none, so just return "default" */
2N/A if (!(*ppcScopes = strdup("default"))) {
2N/A slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A return (SLP_OK);
2N/A }
2N/A
2N/A /* we now have a btree, each leaf of which is a unique scope */
2N/A slp_twalk(stree, collect_scopes, 0, (void *) ppcScopes);
2N/A
2N/A /* unescape scopes list */
2N/A if ((err = slp_unescape(*ppcScopes, &unesc_reply, SLP_FALSE, '%'))
2N/A == SLP_OK) {
2N/A free(*ppcScopes);
2N/A *ppcScopes = unesc_reply;
2N/A } else {
2N/A free(unesc_reply);
2N/A }
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Finds scopes according to the adminstrative scoping model. A
2N/A * comma-separated list of scopes is returned in *ppcScopes; the
2N/A * caller must free *ppcScopes.
2N/A * If the return_default parameter is true, and no scopes are found,
2N/A * *ppcScopes will be set to 'default', otherwise, *ppcScopes will
2N/A * be NULL. This helps simplify internal memory management.
2N/A */
2N/ASLPError slp_administrative_scopes(char **ppcScopes,
2N/A SLPBoolean return_default) {
2N/A const char *useScopes;
2N/A
2N/A *ppcScopes = NULL;
2N/A
2N/A /* @@@ first try DHCP */
2N/A /* next try the useScopes property */
2N/A useScopes = SLPGetProperty(SLP_CONFIG_USESCOPES);
2N/A
2N/A if (useScopes && *useScopes) {
2N/A if (!(*ppcScopes = strdup(useScopes))) {
2N/A slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A return (SLP_OK);
2N/A }
2N/A
2N/A /* found none, so just return "default" */
2N/A if (return_default && !(*ppcScopes = strdup("default"))) {
2N/A slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A return (SLP_OK);
2N/A}
2N/A
2N/A/*
2N/A * This function operates on the same btree as the collate_scopes().
2N/A * The difference is that this one is called for each
2N/A * SAAdvert recieved.
2N/A */
2N/A/* ARGSUSED */
2N/Astatic SLPBoolean saadvert_callback(SLPHandle hp, char *scopes,
2N/A SLPError err, void **stree) {
2N/A char *s, *tstate;
2N/A
2N/A if (err != SLP_OK) {
2N/A return (SLP_TRUE);
2N/A }
2N/A
2N/A for (
2N/A s = strtok_r((char *)scopes, ",", &tstate);
2N/A s;
2N/A s = strtok_r(NULL, ",", &tstate)) {
2N/A
2N/A char *ascope, **srch;
2N/A
2N/A if (!(ascope = strdup(s))) { /* no memory! */
2N/A slp_err(LOG_CRIT, 0, "collate_scopes",
2N/A "out of memory");
2N/A return (SLP_TRUE);
2N/A }
2N/A
2N/A srch = slp_tsearch(
2N/A (void *) ascope, stree,
2N/A (int (*)(const void *, const void *)) slp_strcasecmp);
2N/A if (*srch != ascope)
2N/A /* scope is already in there, so just free ascope */
2N/A free(ascope);
2N/A }
2N/A
2N/A return (SLP_TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Generates an SAAdvert solicitation, and returns any scopes found
2N/A * from all recieved SAAdverts in stree. stree must be a btree
2N/A * structure.
2N/A */
2N/Astatic SLPError SAAdvert_for_scopes(SLPHandle hSLP, void **stree) {
2N/A SLPError err;
2N/A SLPBoolean sync_state;
2N/A slp_handle_impl_t *hp = (slp_handle_impl_t *)hSLP;
2N/A char *predicate;
2N/A const char *type_hint;
2N/A
2N/A /* get type hint, if set */
2N/A if ((type_hint = SLPGetProperty(SLP_CONFIG_TYPEHINT)) != NULL &&
2N/A *type_hint != 0) {
2N/A
2N/A size_t hintlen = strlen(type_hint);
2N/A size_t predlen = strlen("(service-type=)");
2N/A
2N/A /* check bounds */
2N/A if (hintlen > (SLP_MAX_STRINGLEN - predlen)) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A if (!(predicate = malloc(hintlen + predlen + 1))) {
2N/A slp_err(LOG_CRIT, 0, "SAAdvert_for_scopes",
2N/A "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A (void) strcpy(predicate, "(service-type=");
2N/A (void) strcat(predicate, type_hint);
2N/A (void) strcat(predicate, ")");
2N/A } else {
2N/A predicate = "";
2N/A type_hint = NULL;
2N/A }
2N/A
2N/A /* No callback for SLPFindScopes, so force synchronous mode only */
2N/A sync_state = hp->async;
2N/A hp->async = SLP_FALSE;
2N/A
2N/A if ((err = slp_start_call(hp)) != SLP_OK)
2N/A return (err);
2N/A
2N/A err = slp_packSrvRqst("service:service-agent", predicate, hp);
2N/A
2N/A if (err == SLP_OK)
2N/A err = slp_ua_common(hSLP, "",
2N/A (SLPGenericAppCB *)saadvert_callback,
2N/A stree,
2N/A (SLPMsgReplyCB *)unpackSAAdvert_scope);
2N/A
2N/A if (type_hint) {
2N/A free(predicate);
2N/A }
2N/A
2N/A if (err != SLP_OK)
2N/A slp_end_call(hp);
2N/A
2N/A /* restore sync state */
2N/A hp->async = sync_state;
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Unpack an SAAdvert and pass each set of scopes into cb.
2N/A */
2N/A/* ARGSUSED */
2N/Astatic SLPBoolean unpackSAAdvert_scope(slp_handle_impl_t *hSLP, char *reply,
2N/A SLPScopeCallback cb, void *cookie,
2N/A void **collator, int *numResults) {
2N/A char *surl, *scopes, *attrs;
2N/A SLPBoolean cont;
2N/A
2N/A if (!reply) {
2N/A cb(hSLP, NULL, SLP_LAST_CALL, cookie);
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A /* tag call as internal; gets all scopes, regardless of maxResults */
2N/A hSLP->internal_call = SLP_TRUE;
2N/A
2N/A if (slp_unpackSAAdvert(reply, &surl, &scopes, &attrs) != SLP_OK) {
2N/A return (SLP_TRUE);
2N/A }
2N/A
2N/A cont = cb(hSLP, scopes, SLP_OK, cookie);
2N/A
2N/A /* revert internal_call tag */
2N/A hSLP->internal_call = SLP_FALSE;
2N/A
2N/A free(surl);
2N/A free(scopes);
2N/A free(attrs);
2N/A
2N/A return (cont);
2N/A}
2N/A
2N/A/*
2N/A * Creates a service request for finding DAs or SAs (based on 'filter'),
2N/A * and sends it to slpd, returning the reply in 'reply'.
2N/A */
2N/ASLPError slp_find_das(const char *filter, char **reply) {
2N/A SLPError err;
2N/A char *msg, hostname[MAXHOSTNAMELEN];
2N/A
2N/A /* Try the cache first */
2N/A if (*reply = slp_find_das_cached(filter)) {
2N/A return (SLP_OK);
2N/A }
2N/A
2N/A /*
2N/A * create a find scopes message:
2N/A * this is a SrvRqst for the type directory-agent.sun.
2N/A */
2N/A /* use the local host's name for the scope */
2N/A (void) gethostname(hostname, MAXHOSTNAMELEN);
2N/A
2N/A err = slp_packSrvRqst_single(
2N/A SLP_SUN_DA_TYPE, hostname, filter, &msg, "en");
2N/A
2N/A if (err == SLP_OK) {
2N/A err = slp_send2slpd(msg, reply);
2N/A free(msg);
2N/A }
2N/A
2N/A /* Add the reply to the cache */
2N/A if (err == SLP_OK) {
2N/A slp_put_das_cached(filter, *reply, slp_get_length(*reply));
2N/A }
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This is called for each URL entry in the DA service reply (sun private).
2N/A * Contained within the cookie is a btree, to which it adds new
2N/A * scopes from the URL entry. The scopes are retrieved from the btree
2N/A * by traversing the tree in SLPFindScopes().
2N/A * SLPHandle h is NULL, so don't touch it!
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic SLPBoolean collate_scopes(SLPHandle h, const char *u,
2N/A unsigned short lifetime,
2N/A SLPError errCode, void *cookie) {
2N/A SLPSrvURL *surl;
2N/A char *s, *tstate, *p, *url;
2N/A void **collator = cookie;
2N/A
2N/A if (errCode != SLP_OK)
2N/A return (SLP_TRUE);
2N/A
2N/A /* dup url so as not to corrupt da cache */
2N/A if (!(url = strdup(u))) {
2N/A slp_err(LOG_CRIT, 0, "collate_scopes", "out of memory");
2N/A return (SLP_FALSE);
2N/A }
2N/A
2N/A /* parse url into a SLPSrvURL struct */
2N/A if (SLPParseSrvURL(url, &surl) != SLP_OK)
2N/A return (SLP_TRUE); /* bad URL; skip it */
2N/A
2N/A /* collate the scopes using the btree stree->scopes: */
2N/A /* skip the 'scopes=' part */
2N/A if (!(p = strchr(surl->s_pcSrvPart, '='))) {
2N/A free(surl);
2N/A return (SLP_TRUE); /* bad URL; skip it */
2N/A }
2N/A p++;
2N/A
2N/A for (
2N/A s = strtok_r(p, ",", &tstate);
2N/A s;
2N/A s = strtok_r(NULL, ",", &tstate)) {
2N/A
2N/A char *ascope, **srch;
2N/A
2N/A if (!(ascope = strdup(s))) { /* no memory! */
2N/A slp_err(LOG_CRIT, 0, "collate_scopes",
2N/A "out of memory");
2N/A free(surl);
2N/A return (SLP_TRUE);
2N/A }
2N/A
2N/A srch = slp_tsearch(
2N/A (void *) ascope, collator,
2N/A (int (*)(const void *, const void *)) slp_strcasecmp);
2N/A if (*srch != ascope)
2N/A /* scope is already in there, so just free ascope */
2N/A free(ascope);
2N/A }
2N/A
2N/A free(url);
2N/A free(surl);
2N/A
2N/A return (SLP_TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Each time we visit a node for the last time, copy that scope into
2N/A * the scope collection and free the scope string and the node.
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic void collect_scopes(void *node, VISIT order, int level, void *cookie) {
2N/A char **scopes = (char **)cookie;
2N/A
2N/A if (order == endorder || order == leaf) {
2N/A char *s = *(char **)node;
2N/A slp_add2list(s, scopes, SLP_FALSE);
2N/A free(s);
2N/A free(node);
2N/A }
2N/A}
2N/A
2N/Avoid SLPFree(void *pvMem) {
2N/A if (pvMem)
2N/A free(pvMem);
2N/A}
2N/A
2N/A/*
2N/A * Escape / Unescape
2N/A */
2N/A
2N/A#define isBadTagChar(c) ((c) == '*' || (c) == '_' || \
2N/A (c) == '\n' || (c) == '\t' || (c) == '\r')
2N/A
2N/A#define isReserved(c) ((c) <= 31 || (c) == '(' || (c) == ')' || \
2N/A (c) == ',' || (c) == '\\' || (c) == '!' || \
2N/A (c) == '<' || (c) == '=' || (c) == '>' || \
2N/A (c) == '~')
2N/A
2N/ASLPError SLPEscape(const char *pcInbuf, char **ppcOutBuf, SLPBoolean isTag) {
2N/A char *buf, *pin, *pout;
2N/A
2N/A if (!pcInbuf || !ppcOutBuf)
2N/A return (SLP_PARAMETER_BAD);
2N/A
2N/A if (!(buf = malloc(strlen(pcInbuf) * 3 + 1))) {
2N/A slp_err(LOG_CRIT, 0, "SLPEscape", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A *ppcOutBuf = buf;
2N/A
2N/A for (pin = (char *)pcInbuf, pout = buf; *pin; ) {
2N/A int len;
2N/A
2N/A /* If char is start of multibyte char, just copy it in */
2N/A if ((len = mblen(pin, MB_CUR_MAX)) > 1) {
2N/A int i;
2N/A for (i = 0; i < len && *pin; i++)
2N/A *pout++ = *pin++;
2N/A continue;
2N/A }
2N/A
2N/A /* check for bad tag */
2N/A if (isTag && isBadTagChar(*pin))
2N/A return (SLP_PARSE_ERROR);
2N/A
2N/A if (isReserved(*pin)) {
2N/A if (isTag)
2N/A return (SLP_PARSE_ERROR);
2N/A (void) sprintf(pout, "\\%.2x", *pin);
2N/A pout += 3;
2N/A pin++;
2N/A } else {
2N/A *pout++ = *pin++;
2N/A }
2N/A }
2N/A *pout = 0;
2N/A
2N/A return (SLP_OK);
2N/A}
2N/A
2N/ASLPError SLPUnescape(const char *pcInbuf, char **ppcOutBuf, SLPBoolean isTag) {
2N/A if (!pcInbuf || !ppcOutBuf)
2N/A return (SLP_PARAMETER_BAD);
2N/A
2N/A return (slp_unescape(pcInbuf, ppcOutBuf, isTag, '\\'));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * The actual unescaping routine; allows for different escape chars.
2N/A */
2N/Astatic SLPError slp_unescape(const char *pcInbuf, char **ppcOutBuf,
2N/A SLPBoolean isTag, const char esc_char) {
2N/A char *buf, *pin, *pout, conv[3];
2N/A
2N/A if (!(buf = malloc(strlen(pcInbuf) * 3 + 1))) {
2N/A slp_err(LOG_CRIT, 0, "SLPEscape", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A *ppcOutBuf = buf;
2N/A
2N/A conv[2] = 0;
2N/A for (pin = (char *)pcInbuf, pout = buf; *pin; ) {
2N/A int len;
2N/A
2N/A /* If char is start of multibyte char, just copy it in */
2N/A if ((len = mblen(pin, MB_CUR_MAX)) > 1) {
2N/A int i;
2N/A for (i = 0; i < len && *pin; i++)
2N/A *pout++ = *pin++;
2N/A continue;
2N/A }
2N/A
2N/A if (*pin == esc_char) {
2N/A if (!pin[1] || !pin[2])
2N/A return (SLP_PARSE_ERROR);
2N/A pin++;
2N/A conv[0] = *pin++;
2N/A conv[1] = *pin++;
2N/A *pout++ = (char)strtol(conv, NULL, 16);
2N/A if (isTag && isBadTagChar(*pout))
2N/A return (SLP_PARSE_ERROR);
2N/A } else {
2N/A *pout++ = *pin++;
2N/A }
2N/A }
2N/A *pout = 0;
2N/A
2N/A return (SLP_OK);
2N/A}
2N/A
2N/A/*
2N/A * Properties
2N/A *
2N/A * All properties are stored in a global tree (prop_table). This
2N/A * tree is created and accessed by slp_tsearch and slp_tfind.
2N/A */
2N/Astruct prop_entry {
2N/A const char *key, *val;
2N/A};
2N/Atypedef struct prop_entry slp_prop_entry_t;
2N/A
2N/A/* Global properties table */
2N/Astatic void *slp_props = NULL;
2N/Astatic mutex_t prop_table_lock = DEFAULTMUTEX;
2N/A
2N/Astatic void setDefaults();
2N/A
2N/Astatic int compare_props(const void *a, const void *b) {
2N/A return (strcmp(
2N/A ((slp_prop_entry_t *)a)->key,
2N/A ((slp_prop_entry_t *)b)->key));
2N/A}
2N/A
2N/Avoid SLPSetProperty(const char *pcName, const char *pcValue) {
2N/A slp_prop_entry_t *pe, **pe2;
2N/A
2N/A if (!slp_props) setDefaults();
2N/A
2N/A if (!pcName || !pcValue) {
2N/A return;
2N/A }
2N/A
2N/A if (!(pe = malloc(sizeof (*pe)))) {
2N/A slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
2N/A return;
2N/A }
2N/A
2N/A /* place the strings under library ownership */
2N/A if (!(pe->key = strdup(pcName))) {
2N/A free(pe);
2N/A slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
2N/A return;
2N/A }
2N/A
2N/A if (!(pe->val = strdup(pcValue))) {
2N/A free((void *) pe->key);
2N/A free(pe);
2N/A slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
2N/A return;
2N/A }
2N/A
2N/A /* is pcName already set? */
2N/A (void) mutex_lock(&prop_table_lock);
2N/A pe2 = slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A if (pe != *pe2) {
2N/A /* this prop is already set; overwrite the old value */
2N/A free((void *) (*pe2)->val);
2N/A (*pe2)->val = pe->val;
2N/A free((void *) pe->key);
2N/A free(pe);
2N/A }
2N/A (void) mutex_unlock(&prop_table_lock);
2N/A}
2N/A
2N/Aconst char *SLPGetProperty(const char *pcName) {
2N/A slp_prop_entry_t pe[1], **ans;
2N/A
2N/A if (!slp_props) setDefaults();
2N/A
2N/A if (!pcName) {
2N/A return (NULL);
2N/A }
2N/A
2N/A pe->key = pcName;
2N/A
2N/A (void) mutex_lock(&prop_table_lock);
2N/A ans = slp_tfind(pe, &slp_props, compare_props);
2N/A (void) mutex_unlock(&prop_table_lock);
2N/A if (ans)
2N/A return ((*ans)->val);
2N/A return (NULL);
2N/A}
2N/A
2N/Astatic void setDefaults() {
2N/A slp_prop_entry_t *pe;
2N/A static mutex_t lock = DEFAULTMUTEX;
2N/A
2N/A (void) mutex_lock(&lock);
2N/A if (slp_props) {
2N/A (void) mutex_unlock(&lock);
2N/A return;
2N/A }
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = strdup(SLP_CONFIG_ISBROADCASTONLY);
2N/A pe->val = strdup("false");
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = strdup(SLP_CONFIG_MULTICASTTTL);
2N/A pe->val = strdup("255");
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = strdup(SLP_CONFIG_MULTICASTMAXWAIT);
2N/A pe->val = strdup("15000");
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = strdup(SLP_CONFIG_DATAGRAMTIMEOUTS);
2N/A pe->val = strdup("2000,2000,2000");
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = strdup(SLP_CONFIG_MULTICASTTIMEOUTS);
2N/A pe->val = strdup("1000,3000,3000,3000,3000");
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = SLP_CONFIG_MTU; pe->val = "1400";
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = strdup(SLP_CONFIG_MAXRESULTS);
2N/A pe->val = strdup("-1");
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = strdup(SLP_CONFIG_SECURITY_ON);
2N/A pe->val = strdup("false");
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A pe = malloc(sizeof (*pe));
2N/A pe->key = strdup(SLP_CONFIG_BYPASS_AUTH);
2N/A pe->val = strdup("false");
2N/A (void) slp_tsearch((void *) pe, &slp_props, compare_props);
2N/A
2N/A slp_readConfig();
2N/A
2N/A (void) mutex_unlock(&lock);
2N/A}
2N/A
2N/Astatic const char *error_strings[] = {
2N/A "OK", /* 0 */
2N/A "Language not supported", /* -1 */
2N/A "Parse error", /* -2 */
2N/A "Invalid registration", /* -3 */
2N/A "Scope not supported", /* -4 */
2N/A "Invalid error number", /* -5 */
2N/A "Authentication absent", /* -6 */
2N/A "Authentication failed", /* -7 */
2N/A "Invalid error number", /* -8 */
2N/A "Invalid error number", /* -9 */
2N/A "Invalid error number", /* -10 */
2N/A "Invalid error number", /* -11 */
2N/A "Invalid error number", /* -12 */
2N/A "Invalid update", /* -13 */
2N/A "Invalid error number", /* -14 */
2N/A "Invalid error number", /* -15 */
2N/A "Invalid error number", /* -16 */
2N/A "Not implemented", /* -17 */
2N/A "Buffer overflow", /* -18 */
2N/A "Network timed out", /* -19 */
2N/A "Network init failed", /* -20 */
2N/A "Memory alloc failed", /* -21 */
2N/A "Parameter bad", /* -22 */
2N/A "Network error", /* -23 */
2N/A "Internal system error", /* -24 */
2N/A "Handle in use", /* -25 */
2N/A "Type error" /* -26 */
2N/A};
2N/A
2N/A#define SLP_MAX_ERR_CNT 26
2N/A
2N/Aconst char *slp_strerror(SLPError err) {
2N/A int abserr;
2N/A const char *str;
2N/A
2N/A if (err == SLP_LAST_CALL) {
2N/A str = "Last call";
2N/A } else if (err == SLP_SECURITY_UNAVAILABLE) {
2N/A str = "Security Implementation Unavailable";
2N/A } else {
2N/A abserr = abs(err);
2N/A if (abserr > SLP_MAX_ERR_CNT) {
2N/A str = "Invalid error number";
2N/A } else {
2N/A str = error_strings[abserr];
2N/A }
2N/A }
2N/A
2N/A return (dgettext(TEXT_DOMAIN, str));
2N/A}