/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Target Lists
* ============
* All UA functions use target lists to select and manage their
* network targets. There are two types of network targets: unicast (uc)
* and multicast (mc) -- multicast will also work for broadcast. This
* module organizes unicast targets into an efficient ordering. The
* targeting structure can be though of as a 2-dimensional matrix, with
* the following axes:
*
* unicast failovers --->
* targets
* |
* |
* \ /
*
* Callers walk down the unicast targets, unicasting to each. If any
* unicast target fails, callers then walk to the right, through failover
* targets until they either find one that works, or there are no more
* failover targets.
*
* The targeting heuristic orders the unicast targets so that those
* DAs which support the greatest number of requested scopes are called
* first, thus minimizing the number of unicasts which need to be done.
* Within groups of DAs supporting the same scope coverage, the DAs are
* sorted according to network proximity relative to the local host:
* DAs on the local host come first, then those on a same subnet, then
* all other (remote) DAs.
*
* A given DA is called no more than once, and failed DAs are skipped
* after they have been marked 'failed'.
*
* All access to a target list is done through the following functions
* and types:
* There are two opaque types:
* slp_target_list_t: A handle to a target list
* slp_target_t: A handle to an individual target. slp_get_target_sin
* will extract an inet address for this target.
*
* There are the following accessor functions:
* slp_new_target_list: creates a new target list for the given scopes,
* and populates with all known DAs for these scopes.
* slp_get_uc_scopes: returns a list of all scopes for which there are
* DAs (and which can thus be used for unicasts)
* slp_get_mc_scopes: returns a list of all scopes for which there are
* no DAs (and which must thus be used for multicasts).
* slp_next_uc_target: Returns a slp_target_t handle for the next unicast
* target, or NULL for none.
* slp_next_failover: Returns the next failover DA for a given target, or
* NULL for none.
* slp_get_target_sin: extracts a sockaddr_in for a given slp_target_t;
* slp_mark_target_used: callers should mark a slp_target_t used after
* successfully communicating with that target.
* slp_mark_target_failed: callers should mark a slp_target_t failed after
* trying and failing to communicate with a target.
* slp_destroy_target_list: destroys and frees a target list and all its
* associated resources.
* slp_fabricate_target: Creates a slp_target_t from a given sockaddr_in.
* This is useful for situations such as when a
* multicast routine needs to hand off to a TCP
* routine (due to overflow), and there is no target
* list available. Fabricated targets should be free'd
* with slp_free_target; the input sin will duplicated
* in the target, so the caller can free it after
* calling slp_fabricate_target.
* slp_free_target: Frees an slp_target_t created by slp_fabricate_target.
* This should not be used to free any other target.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <slp-internal.h>
#include <slp_net_utils.h>
typedef enum {
} slp_net_prox;
struct da_node {
char *scopes;
int coverage;
};
struct scope_targets {
};
struct target_list {
char *uc_scopes;
char *mc_scopes;
char *all_scopes;
};
char *, slp_net_prox, int);
static void format_query(char *, const char *);
slp_target_list_t **handle) {
int scope_cnt;
char *p;
/* count the number of scopes in the list */
scope_cnt = 0;
for (p = (char *)scopes; p; p++) {
p = slp_utf_strchr(p, ',');
scope_cnt++;
if (!p)
break;
}
/* create a new target list */
return (SLP_MEMORY_ALLOC_FAILED);
}
return (SLP_MEMORY_ALLOC_FAILED);
}
return (SLP_MEMORY_ALLOC_FAILED);
}
/* As scopes are added to uc list, they are removed from the mc list */
return (SLP_MEMORY_ALLOC_FAILED);
}
if (hp->force_multicast) {
/* all scopes remain multicast scopes; useful for SAAdverts */
return (SLP_OK);
}
/* DAs from active and passive discovery */
(scope_cnt *
return (SLP_MEMORY_ALLOC_FAILED);
}
err != SLP_NETWORK_ERROR) {
return (err);
}
/* Unpack the reply */
if (reply) {
/* tag call as internal */
/* invoke last call */
/* revert internal call tag */
}
/*
* tl->DAs now points to a list of DAs sorted by the number of
* relevant scopes they serve. Using this ordering, populate the
* scope array lists.
*/
return (SLP_OK);
}
}
}
struct scope_targets *p;
return (NULL);
/* find the next unused target */
/* get next failover */
return (p);
}
/* else nothing more we can do */
}
}
return (NULL);
}
struct scope_targets *p = (struct scope_targets *)h;
return (NULL); /* already did this scope */
return (p);
}
return (NULL);
}
struct scope_targets *p = (struct scope_targets *)h;
}
struct scope_targets *p = (struct scope_targets *)h;
}
struct scope_targets *p = (struct scope_targets *)h;
}
return (NULL);
}
return (NULL);
}
return (st);
}
if (!t)
return;
free(t);
}
int i;
/* free da node list */
}
/* free scope target linked lists */
}
}
/* free scope array */
/* free any char * lists in use */
/* free the target list struct */
}
char *p, *s;
int i;
/*
* for each scope in tl->uc_scopes:
* add this DA if it serves the scope.
*/
i = 0;
p = slp_utf_strchr(s, ',');
if (p)
*p = 0;
/* add this DA node to this scope's target list */
"out of memory");
return;
}
/* find the end of the target list */
}
if (stp)
else
}
if (p)
*p++ = ',';
i++;
}
}
return;
}
/* find its place in the list */
if (!(*tel)) {
return;
}
if (c >= p->coverage) {
/* found a coverage grouping; now sort by proximity */
p = p->next;
if (!p) {
break;
}
/* add it here */
if (p->prev)
else
/* we're at the head */
return;
}
/* didn't find a place in the list, so add it at the end */
p = p->next;
}
/*ARGSUSED*/
unsigned short lifetime,
return (SLP_TRUE);
/* dup url so as not to corrupt da cache */
return (SLP_FALSE);
}
/* parse url into a SLPSrvURL struct */
return (SLP_TRUE); /* bad URL; skip it */
}
/* determine proximity */
goto cleanup;
}
} else {
}
/*
* sort the DAs into the entry list, ranked by the number of
* relevant scopes they serve (coverage).
*/
coverage = 0;
/* URL part should be of the form 'scopes=...' */
goto cleanup;
}
sscopes++;
/* cut off host scope at end */
/* skip the =[hostname] at the end */
*sscopes_end = 0;
}
/* copy out the scopes part, since url will be freed after this call */
return (SLP_FALSE);
}
for (s = tl->all_scopes; s; s = p) {
p = slp_utf_strchr(s, ',');
if (p)
*p = 0;
if (slp_onlist(s, sscopes)) {
/* add to uc list; remove from mc list */
coverage++;
}
if (p)
*p++ = ',';
}
if (coverage)
return (SLP_TRUE);
}
/*
* Takes a scopes list of the form 's1,s2,s3,...' and formats it into
* an LDAP search filter of the form '(|(SCOPETAG=s1)(SCOPETAG=s2)...)'.
* 'scopes' contains the scopes list; 'q' is a buffer allocated
* by the caller into which the result will be placed.
*/
char *p, *s;
*q++ = '('; *q++ = '&';
if (more_than_one) {
*q++ = '('; *q++ = '|';
}
for (p = s = (char *)scopes; p; s = p) {
*q++ = '(';
(void) strcpy(q, SLP_SUN_SCOPES_TAG);
q += strlen(SLP_SUN_SCOPES_TAG);
*q++ = '=';
p = slp_utf_strchr(s, ',');
if (p) {
(void) memcpy(q, s, p - s);
q += (p - s);
p++;
} else {
(void) strcpy(q, s);
q += strlen(s);
}
*q++ = ')';
}
if (more_than_one) {
*q++ = ')';
}
*q++ = '(';
(void) strcpy(q, SLP_SUN_VERSION_TAG);
q += strlen(SLP_SUN_VERSION_TAG);
*q++ = '=';
*q++ = '2';
*q++ = ')';
*q++ = ')';
*q = 0;
}