1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Target Lists 31*7c478bd9Sstevel@tonic-gate * ============ 32*7c478bd9Sstevel@tonic-gate * All UA functions use target lists to select and manage their 33*7c478bd9Sstevel@tonic-gate * network targets. There are two types of network targets: unicast (uc) 34*7c478bd9Sstevel@tonic-gate * and multicast (mc) -- multicast will also work for broadcast. This 35*7c478bd9Sstevel@tonic-gate * module organizes unicast targets into an efficient ordering. The 36*7c478bd9Sstevel@tonic-gate * targeting structure can be though of as a 2-dimensional matrix, with 37*7c478bd9Sstevel@tonic-gate * the following axes: 38*7c478bd9Sstevel@tonic-gate * 39*7c478bd9Sstevel@tonic-gate * unicast failovers ---> 40*7c478bd9Sstevel@tonic-gate * targets 41*7c478bd9Sstevel@tonic-gate * | 42*7c478bd9Sstevel@tonic-gate * | 43*7c478bd9Sstevel@tonic-gate * \ / 44*7c478bd9Sstevel@tonic-gate * 45*7c478bd9Sstevel@tonic-gate * Callers walk down the unicast targets, unicasting to each. If any 46*7c478bd9Sstevel@tonic-gate * unicast target fails, callers then walk to the right, through failover 47*7c478bd9Sstevel@tonic-gate * targets until they either find one that works, or there are no more 48*7c478bd9Sstevel@tonic-gate * failover targets. 49*7c478bd9Sstevel@tonic-gate * 50*7c478bd9Sstevel@tonic-gate * The targeting heuristic orders the unicast targets so that those 51*7c478bd9Sstevel@tonic-gate * DAs which support the greatest number of requested scopes are called 52*7c478bd9Sstevel@tonic-gate * first, thus minimizing the number of unicasts which need to be done. 53*7c478bd9Sstevel@tonic-gate * Within groups of DAs supporting the same scope coverage, the DAs are 54*7c478bd9Sstevel@tonic-gate * sorted according to network proximity relative to the local host: 55*7c478bd9Sstevel@tonic-gate * DAs on the local host come first, then those on a same subnet, then 56*7c478bd9Sstevel@tonic-gate * all other (remote) DAs. 57*7c478bd9Sstevel@tonic-gate * 58*7c478bd9Sstevel@tonic-gate * A given DA is called no more than once, and failed DAs are skipped 59*7c478bd9Sstevel@tonic-gate * after they have been marked 'failed'. 60*7c478bd9Sstevel@tonic-gate * 61*7c478bd9Sstevel@tonic-gate * All access to a target list is done through the following functions 62*7c478bd9Sstevel@tonic-gate * and types: 63*7c478bd9Sstevel@tonic-gate * There are two opaque types: 64*7c478bd9Sstevel@tonic-gate * slp_target_list_t: A handle to a target list 65*7c478bd9Sstevel@tonic-gate * slp_target_t: A handle to an individual target. slp_get_target_sin 66*7c478bd9Sstevel@tonic-gate * will extract an inet address for this target. 67*7c478bd9Sstevel@tonic-gate * 68*7c478bd9Sstevel@tonic-gate * There are the following accessor functions: 69*7c478bd9Sstevel@tonic-gate * slp_new_target_list: creates a new target list for the given scopes, 70*7c478bd9Sstevel@tonic-gate * and populates with all known DAs for these scopes. 71*7c478bd9Sstevel@tonic-gate * slp_get_uc_scopes: returns a list of all scopes for which there are 72*7c478bd9Sstevel@tonic-gate * DAs (and which can thus be used for unicasts) 73*7c478bd9Sstevel@tonic-gate * slp_get_mc_scopes: returns a list of all scopes for which there are 74*7c478bd9Sstevel@tonic-gate * no DAs (and which must thus be used for multicasts). 75*7c478bd9Sstevel@tonic-gate * slp_next_uc_target: Returns a slp_target_t handle for the next unicast 76*7c478bd9Sstevel@tonic-gate * target, or NULL for none. 77*7c478bd9Sstevel@tonic-gate * slp_next_failover: Returns the next failover DA for a given target, or 78*7c478bd9Sstevel@tonic-gate * NULL for none. 79*7c478bd9Sstevel@tonic-gate * slp_get_target_sin: extracts a sockaddr_in for a given slp_target_t; 80*7c478bd9Sstevel@tonic-gate * slp_mark_target_used: callers should mark a slp_target_t used after 81*7c478bd9Sstevel@tonic-gate * successfully communicating with that target. 82*7c478bd9Sstevel@tonic-gate * slp_mark_target_failed: callers should mark a slp_target_t failed after 83*7c478bd9Sstevel@tonic-gate * trying and failing to communicate with a target. 84*7c478bd9Sstevel@tonic-gate * slp_destroy_target_list: destroys and frees a target list and all its 85*7c478bd9Sstevel@tonic-gate * associated resources. 86*7c478bd9Sstevel@tonic-gate * slp_fabricate_target: Creates a slp_target_t from a given sockaddr_in. 87*7c478bd9Sstevel@tonic-gate * This is useful for situations such as when a 88*7c478bd9Sstevel@tonic-gate * multicast routine needs to hand off to a TCP 89*7c478bd9Sstevel@tonic-gate * routine (due to overflow), and there is no target 90*7c478bd9Sstevel@tonic-gate * list available. Fabricated targets should be free'd 91*7c478bd9Sstevel@tonic-gate * with slp_free_target; the input sin will duplicated 92*7c478bd9Sstevel@tonic-gate * in the target, so the caller can free it after 93*7c478bd9Sstevel@tonic-gate * calling slp_fabricate_target. 94*7c478bd9Sstevel@tonic-gate * slp_free_target: Frees an slp_target_t created by slp_fabricate_target. 95*7c478bd9Sstevel@tonic-gate * This should not be used to free any other target. 96*7c478bd9Sstevel@tonic-gate * 97*7c478bd9Sstevel@tonic-gate */ 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate #include <stdio.h> 100*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 101*7c478bd9Sstevel@tonic-gate #include <string.h> 102*7c478bd9Sstevel@tonic-gate #include <syslog.h> 103*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 104*7c478bd9Sstevel@tonic-gate #include <slp-internal.h> 105*7c478bd9Sstevel@tonic-gate #include <slp_net_utils.h> 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate typedef enum { 108*7c478bd9Sstevel@tonic-gate SLP_REMOTE_PROX = 0, /* remote to local host */ 109*7c478bd9Sstevel@tonic-gate SLP_SUBNET_PROX = 1, /* on same subnet as local host */ 110*7c478bd9Sstevel@tonic-gate SLP_LOCAL_PROX = 2 /* on local host */ 111*7c478bd9Sstevel@tonic-gate } slp_net_prox; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate struct da_node { 114*7c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 115*7c478bd9Sstevel@tonic-gate char *scopes; 116*7c478bd9Sstevel@tonic-gate SLPBoolean used, failed; 117*7c478bd9Sstevel@tonic-gate int coverage; 118*7c478bd9Sstevel@tonic-gate slp_net_prox proximity; 119*7c478bd9Sstevel@tonic-gate struct da_node *next, *prev; 120*7c478bd9Sstevel@tonic-gate }; 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate struct scope_targets { 123*7c478bd9Sstevel@tonic-gate struct da_node *da; 124*7c478bd9Sstevel@tonic-gate struct scope_targets *next; 125*7c478bd9Sstevel@tonic-gate }; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate struct target_list { 128*7c478bd9Sstevel@tonic-gate struct scope_targets **scopes; 129*7c478bd9Sstevel@tonic-gate struct scope_targets **state; 130*7c478bd9Sstevel@tonic-gate char *uc_scopes; 131*7c478bd9Sstevel@tonic-gate char *mc_scopes; 132*7c478bd9Sstevel@tonic-gate char *all_scopes; 133*7c478bd9Sstevel@tonic-gate struct da_node *DAs; 134*7c478bd9Sstevel@tonic-gate }; 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate static void add2scopes_list(struct da_node *, struct target_list *); 137*7c478bd9Sstevel@tonic-gate static void add_da_entry(struct da_node **, struct sockaddr_in *, 138*7c478bd9Sstevel@tonic-gate char *, slp_net_prox, int); 139*7c478bd9Sstevel@tonic-gate static SLPSrvURLCallback collect_DAs; 140*7c478bd9Sstevel@tonic-gate static void format_query(char *, const char *); 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate SLPError slp_new_target_list(slp_handle_impl_t *hp, const char *scopes, 143*7c478bd9Sstevel@tonic-gate slp_target_list_t **handle) { 144*7c478bd9Sstevel@tonic-gate struct target_list *tl; 145*7c478bd9Sstevel@tonic-gate int scope_cnt; 146*7c478bd9Sstevel@tonic-gate char *p; 147*7c478bd9Sstevel@tonic-gate struct da_node *te; 148*7c478bd9Sstevel@tonic-gate char *query, *reply; 149*7c478bd9Sstevel@tonic-gate SLPError err; 150*7c478bd9Sstevel@tonic-gate void *collator = NULL; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* count the number of scopes in the list */ 153*7c478bd9Sstevel@tonic-gate scope_cnt = 0; 154*7c478bd9Sstevel@tonic-gate for (p = (char *)scopes; p; p++) { 155*7c478bd9Sstevel@tonic-gate p = slp_utf_strchr(p, ','); 156*7c478bd9Sstevel@tonic-gate scope_cnt++; 157*7c478bd9Sstevel@tonic-gate if (!p) 158*7c478bd9Sstevel@tonic-gate break; 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate /* create a new target list */ 162*7c478bd9Sstevel@tonic-gate if (!(tl = calloc(1, sizeof (*tl)))) { 163*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_new_target_list", "out of memory"); 164*7c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED); 165*7c478bd9Sstevel@tonic-gate } 166*7c478bd9Sstevel@tonic-gate tl->DAs = NULL; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate if (!(tl->scopes = calloc(scope_cnt + 1, sizeof (*(tl->scopes))))) { 169*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_new_target_list", "out of memory"); 170*7c478bd9Sstevel@tonic-gate free(tl); 171*7c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate tl->uc_scopes = NULL; 174*7c478bd9Sstevel@tonic-gate tl->state = tl->scopes; 175*7c478bd9Sstevel@tonic-gate if (!(tl->all_scopes = strdup(scopes))) { 176*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_new_target_list", "out of memory"); 177*7c478bd9Sstevel@tonic-gate free(tl->scopes); free(tl); 178*7c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED); 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate /* As scopes are added to uc list, they are removed from the mc list */ 181*7c478bd9Sstevel@tonic-gate if (!(tl->mc_scopes = strdup(scopes))) { 182*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_new_target_list", "out of memory"); 183*7c478bd9Sstevel@tonic-gate free(tl->scopes); free(tl->all_scopes); free(tl); 184*7c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate if (hp->force_multicast) { 188*7c478bd9Sstevel@tonic-gate /* all scopes remain multicast scopes; useful for SAAdverts */ 189*7c478bd9Sstevel@tonic-gate *handle = tl; 190*7c478bd9Sstevel@tonic-gate return (SLP_OK); 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate /* DAs from active and passive discovery */ 194*7c478bd9Sstevel@tonic-gate if (!(query = malloc(strlen(scopes) - 195*7c478bd9Sstevel@tonic-gate (scope_cnt - 1) + /* exclude commas */ 196*7c478bd9Sstevel@tonic-gate strlen(SLP_SUN_VERSION_TAG) + 197*7c478bd9Sstevel@tonic-gate strlen("(&(=2)(|))") + 1 + 198*7c478bd9Sstevel@tonic-gate (scope_cnt * 199*7c478bd9Sstevel@tonic-gate (strlen(SLP_SUN_SCOPES_TAG) + 200*7c478bd9Sstevel@tonic-gate strlen("(=)")))))) { /* (scopes=) */ 201*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_new_target_list", "out of memory"); 202*7c478bd9Sstevel@tonic-gate free(tl->scopes); 203*7c478bd9Sstevel@tonic-gate free(tl->all_scopes); 204*7c478bd9Sstevel@tonic-gate free(tl->mc_scopes); 205*7c478bd9Sstevel@tonic-gate free(tl); 206*7c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED); 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate format_query(query, scopes); 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate if ((err = slp_find_das(query, &reply)) != SLP_OK && 211*7c478bd9Sstevel@tonic-gate err != SLP_NETWORK_ERROR) { 212*7c478bd9Sstevel@tonic-gate free(tl->scopes); 213*7c478bd9Sstevel@tonic-gate free(tl->all_scopes); 214*7c478bd9Sstevel@tonic-gate free(tl->mc_scopes); 215*7c478bd9Sstevel@tonic-gate free(tl); 216*7c478bd9Sstevel@tonic-gate free(query); 217*7c478bd9Sstevel@tonic-gate return (err); 218*7c478bd9Sstevel@tonic-gate } 219*7c478bd9Sstevel@tonic-gate free(query); 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* Unpack the reply */ 222*7c478bd9Sstevel@tonic-gate if (reply) { 223*7c478bd9Sstevel@tonic-gate int numResults = 0; /* placeholder; not actually used */ 224*7c478bd9Sstevel@tonic-gate /* tag call as internal */ 225*7c478bd9Sstevel@tonic-gate hp->internal_call = SLP_TRUE; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate (void) slp_unpackSrvReply(hp, reply, collect_DAs, 228*7c478bd9Sstevel@tonic-gate tl, &collator, &numResults); 229*7c478bd9Sstevel@tonic-gate free(reply); 230*7c478bd9Sstevel@tonic-gate /* invoke last call */ 231*7c478bd9Sstevel@tonic-gate (void) slp_unpackSrvReply(hp, NULL, collect_DAs, 232*7c478bd9Sstevel@tonic-gate tl, &collator, &numResults); 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* revert internal call tag */ 235*7c478bd9Sstevel@tonic-gate hp->internal_call = SLP_FALSE; 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate /* 239*7c478bd9Sstevel@tonic-gate * tl->DAs now points to a list of DAs sorted by the number of 240*7c478bd9Sstevel@tonic-gate * relevant scopes they serve. Using this ordering, populate the 241*7c478bd9Sstevel@tonic-gate * scope array lists. 242*7c478bd9Sstevel@tonic-gate */ 243*7c478bd9Sstevel@tonic-gate for (te = tl->DAs; te; te = te->next) 244*7c478bd9Sstevel@tonic-gate add2scopes_list(te, tl); 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate *handle = tl; 247*7c478bd9Sstevel@tonic-gate return (SLP_OK); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate const char *slp_get_uc_scopes(slp_target_list_t *h) { 251*7c478bd9Sstevel@tonic-gate struct target_list *tl = (struct target_list *)h; 252*7c478bd9Sstevel@tonic-gate return (tl->uc_scopes); 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate const char *slp_get_mc_scopes(slp_target_list_t *h) { 256*7c478bd9Sstevel@tonic-gate struct target_list *tl = (struct target_list *)h; 257*7c478bd9Sstevel@tonic-gate return (tl->mc_scopes); 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate slp_target_t *slp_next_uc_target(slp_target_list_t *h) { 261*7c478bd9Sstevel@tonic-gate struct scope_targets *p; 262*7c478bd9Sstevel@tonic-gate struct target_list *tl = (struct target_list *)h; 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate if (!(*tl->state)) 265*7c478bd9Sstevel@tonic-gate return (NULL); 266*7c478bd9Sstevel@tonic-gate /* find the next unused target */ 267*7c478bd9Sstevel@tonic-gate for (; *tl->state; tl->state++) { 268*7c478bd9Sstevel@tonic-gate if (!(*tl->state)->da->used && !(*tl->state)->da->failed) 269*7c478bd9Sstevel@tonic-gate return (*tl->state++); 270*7c478bd9Sstevel@tonic-gate if ((*tl->state)->da->failed) { 271*7c478bd9Sstevel@tonic-gate /* get next failover */ 272*7c478bd9Sstevel@tonic-gate if (p = slp_next_failover(*tl->state)) { 273*7c478bd9Sstevel@tonic-gate tl->state++; 274*7c478bd9Sstevel@tonic-gate return (p); 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate /* else nothing more we can do */ 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate return (NULL); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate slp_target_t *slp_next_failover(slp_target_t *h) { 283*7c478bd9Sstevel@tonic-gate struct scope_targets *p = (struct scope_targets *)h; 284*7c478bd9Sstevel@tonic-gate for (p = p->next; p; p = p->next) { 285*7c478bd9Sstevel@tonic-gate if (p->da->used) 286*7c478bd9Sstevel@tonic-gate return (NULL); /* already did this scope */ 287*7c478bd9Sstevel@tonic-gate if (!p->da->used && !p->da->failed) 288*7c478bd9Sstevel@tonic-gate return (p); 289*7c478bd9Sstevel@tonic-gate } 290*7c478bd9Sstevel@tonic-gate return (NULL); 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate void *slp_get_target_sin(slp_target_t *h) { 294*7c478bd9Sstevel@tonic-gate struct scope_targets *p = (struct scope_targets *)h; 295*7c478bd9Sstevel@tonic-gate return (void *)(p ? &(p->da->sin) : NULL); 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate void slp_mark_target_used(slp_target_t *h) { 299*7c478bd9Sstevel@tonic-gate struct scope_targets *p = (struct scope_targets *)h; 300*7c478bd9Sstevel@tonic-gate p->da->used = SLP_TRUE; 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate void slp_mark_target_failed(slp_target_t *h) { 304*7c478bd9Sstevel@tonic-gate struct scope_targets *p = (struct scope_targets *)h; 305*7c478bd9Sstevel@tonic-gate p->da->failed = SLP_TRUE; 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate slp_target_t *slp_fabricate_target(void *s) { 309*7c478bd9Sstevel@tonic-gate struct da_node *dn; 310*7c478bd9Sstevel@tonic-gate struct scope_targets *st; 311*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin = (struct sockaddr_in *)s; 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate if (!(st = malloc(sizeof (*st)))) { 314*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_fabricate_target", "out of memory"); 315*7c478bd9Sstevel@tonic-gate return (NULL); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate if (!(dn = malloc(sizeof (*dn)))) { 318*7c478bd9Sstevel@tonic-gate free(st); 319*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_fabricate_target", "out of memory"); 320*7c478bd9Sstevel@tonic-gate return (NULL); 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate (void) memcpy(&(dn->sin), sin, sizeof (dn->sin)); 323*7c478bd9Sstevel@tonic-gate dn->used = dn->failed = SLP_FALSE; 324*7c478bd9Sstevel@tonic-gate dn->coverage = 0; 325*7c478bd9Sstevel@tonic-gate dn->proximity = SLP_REMOTE_PROX; 326*7c478bd9Sstevel@tonic-gate dn->next = dn->prev = NULL; 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate st->da = dn; 329*7c478bd9Sstevel@tonic-gate st->next = NULL; 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate return (st); 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate void slp_free_target(slp_target_t *target) { 335*7c478bd9Sstevel@tonic-gate struct scope_targets *t = (struct scope_targets *)target; 336*7c478bd9Sstevel@tonic-gate if (!t) 337*7c478bd9Sstevel@tonic-gate return; 338*7c478bd9Sstevel@tonic-gate free(t->da); 339*7c478bd9Sstevel@tonic-gate free(t); 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate void slp_destroy_target_list(slp_target_list_t *h) { 343*7c478bd9Sstevel@tonic-gate struct da_node *das, *dap; 344*7c478bd9Sstevel@tonic-gate int i; 345*7c478bd9Sstevel@tonic-gate struct target_list *tl = (struct target_list *)h; 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate /* free da node list */ 348*7c478bd9Sstevel@tonic-gate for (das = tl->DAs; das; das = dap) { 349*7c478bd9Sstevel@tonic-gate dap = das->next; 350*7c478bd9Sstevel@tonic-gate free(das->scopes); 351*7c478bd9Sstevel@tonic-gate free(das); 352*7c478bd9Sstevel@tonic-gate } 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate /* free scope target linked lists */ 355*7c478bd9Sstevel@tonic-gate for (i = 0; tl->scopes[i]; i++) { 356*7c478bd9Sstevel@tonic-gate struct scope_targets *sts, *stp; 357*7c478bd9Sstevel@tonic-gate for (sts = tl->scopes[i]; sts; sts = stp) { 358*7c478bd9Sstevel@tonic-gate stp = sts->next; 359*7c478bd9Sstevel@tonic-gate free(sts); 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* free scope array */ 364*7c478bd9Sstevel@tonic-gate free(tl->scopes); 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate /* free any char * lists in use */ 367*7c478bd9Sstevel@tonic-gate if (tl->uc_scopes) 368*7c478bd9Sstevel@tonic-gate free(tl->uc_scopes); 369*7c478bd9Sstevel@tonic-gate if (tl->mc_scopes) 370*7c478bd9Sstevel@tonic-gate free(tl->mc_scopes); 371*7c478bd9Sstevel@tonic-gate free(tl->all_scopes); 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate /* free the target list struct */ 374*7c478bd9Sstevel@tonic-gate free(tl); 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate static void add2scopes_list(struct da_node *te, struct target_list *tl) { 378*7c478bd9Sstevel@tonic-gate struct scope_targets **scopes = tl->scopes; 379*7c478bd9Sstevel@tonic-gate char *p, *s; 380*7c478bd9Sstevel@tonic-gate int i; 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* 383*7c478bd9Sstevel@tonic-gate * for each scope in tl->uc_scopes: 384*7c478bd9Sstevel@tonic-gate * add this DA if it serves the scope. 385*7c478bd9Sstevel@tonic-gate */ 386*7c478bd9Sstevel@tonic-gate i = 0; 387*7c478bd9Sstevel@tonic-gate for (s = tl->uc_scopes; s; s = p) { 388*7c478bd9Sstevel@tonic-gate p = slp_utf_strchr(s, ','); 389*7c478bd9Sstevel@tonic-gate if (p) 390*7c478bd9Sstevel@tonic-gate *p = 0; 391*7c478bd9Sstevel@tonic-gate if (slp_onlist(s, te->scopes)) { 392*7c478bd9Sstevel@tonic-gate struct scope_targets *st, *stp; 393*7c478bd9Sstevel@tonic-gate /* add this DA node to this scope's target list */ 394*7c478bd9Sstevel@tonic-gate if (!(st = malloc(sizeof (*st)))) { 395*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "add2scopes_list", 396*7c478bd9Sstevel@tonic-gate "out of memory"); 397*7c478bd9Sstevel@tonic-gate return; 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate st->da = te; 400*7c478bd9Sstevel@tonic-gate st->next = NULL; 401*7c478bd9Sstevel@tonic-gate /* find the end of the target list */ 402*7c478bd9Sstevel@tonic-gate for (stp = scopes[i]; stp && stp->next; ) { 403*7c478bd9Sstevel@tonic-gate stp = stp->next; 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate if (stp) 406*7c478bd9Sstevel@tonic-gate stp->next = st; 407*7c478bd9Sstevel@tonic-gate else 408*7c478bd9Sstevel@tonic-gate scopes[i] = st; 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate if (p) 411*7c478bd9Sstevel@tonic-gate *p++ = ','; 412*7c478bd9Sstevel@tonic-gate i++; 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate static void add_da_entry(struct da_node **tel, struct sockaddr_in *sin, 417*7c478bd9Sstevel@tonic-gate char *scopes, slp_net_prox proximity, int c) { 418*7c478bd9Sstevel@tonic-gate struct da_node *te, *p; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate if (!(te = malloc(sizeof (*te)))) { 421*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "add_da_entry", "out of memory"); 422*7c478bd9Sstevel@tonic-gate return; 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate te->scopes = scopes; 425*7c478bd9Sstevel@tonic-gate te->coverage = c; 426*7c478bd9Sstevel@tonic-gate te->proximity = proximity; 427*7c478bd9Sstevel@tonic-gate (void) memcpy(&(te->sin), sin, sizeof (te->sin)); 428*7c478bd9Sstevel@tonic-gate te->used = SLP_FALSE; 429*7c478bd9Sstevel@tonic-gate te->failed = SLP_FALSE; 430*7c478bd9Sstevel@tonic-gate te->prev = NULL; 431*7c478bd9Sstevel@tonic-gate te->next = NULL; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate /* find its place in the list */ 434*7c478bd9Sstevel@tonic-gate if (!(*tel)) { 435*7c478bd9Sstevel@tonic-gate *tel = te; 436*7c478bd9Sstevel@tonic-gate return; 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate for (p = *tel; p; p = p->next) 439*7c478bd9Sstevel@tonic-gate if (c >= p->coverage) { 440*7c478bd9Sstevel@tonic-gate /* found a coverage grouping; now sort by proximity */ 441*7c478bd9Sstevel@tonic-gate for (; p && proximity < p->proximity; ) 442*7c478bd9Sstevel@tonic-gate p = p->next; 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate if (!p) { 445*7c478bd9Sstevel@tonic-gate break; 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate /* add it here */ 449*7c478bd9Sstevel@tonic-gate te->next = p; 450*7c478bd9Sstevel@tonic-gate te->prev = p->prev; 451*7c478bd9Sstevel@tonic-gate if (p->prev) 452*7c478bd9Sstevel@tonic-gate p->prev->next = te; 453*7c478bd9Sstevel@tonic-gate else 454*7c478bd9Sstevel@tonic-gate /* we're at the head */ 455*7c478bd9Sstevel@tonic-gate (*tel) = te; 456*7c478bd9Sstevel@tonic-gate p->prev = te; 457*7c478bd9Sstevel@tonic-gate return; 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate /* didn't find a place in the list, so add it at the end */ 461*7c478bd9Sstevel@tonic-gate for (p = *tel; p->next; ) 462*7c478bd9Sstevel@tonic-gate p = p->next; 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate p->next = te; 465*7c478bd9Sstevel@tonic-gate te->prev = p; 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 469*7c478bd9Sstevel@tonic-gate static SLPBoolean collect_DAs(SLPHandle h, const char *u, 470*7c478bd9Sstevel@tonic-gate unsigned short lifetime, 471*7c478bd9Sstevel@tonic-gate SLPError errCode, void *cookie) { 472*7c478bd9Sstevel@tonic-gate SLPSrvURL *surl = NULL; 473*7c478bd9Sstevel@tonic-gate char *s, *p, *sscopes, *sscopes_end, *url; 474*7c478bd9Sstevel@tonic-gate int coverage, proximity; 475*7c478bd9Sstevel@tonic-gate struct sockaddr_in sin[1]; 476*7c478bd9Sstevel@tonic-gate struct target_list *tl = (struct target_list *)cookie; 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate if (errCode != SLP_OK) 479*7c478bd9Sstevel@tonic-gate return (SLP_TRUE); 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate /* dup url so as not to corrupt da cache */ 482*7c478bd9Sstevel@tonic-gate if (!(url = strdup(u))) { 483*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "collect_DAs", "out of memory"); 484*7c478bd9Sstevel@tonic-gate return (SLP_FALSE); 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate /* parse url into a SLPSrvURL struct */ 488*7c478bd9Sstevel@tonic-gate if (SLPParseSrvURL(url, &surl) != SLP_OK) { 489*7c478bd9Sstevel@tonic-gate return (SLP_TRUE); /* bad URL; skip it */ 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate /* determine proximity */ 493*7c478bd9Sstevel@tonic-gate if (slp_surl2sin(surl, sin) != SLP_OK) { 494*7c478bd9Sstevel@tonic-gate goto cleanup; 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate if (slp_on_localhost(h, sin->sin_addr)) { 497*7c478bd9Sstevel@tonic-gate proximity = SLP_LOCAL_PROX; 498*7c478bd9Sstevel@tonic-gate } else if (slp_on_subnet(h, sin->sin_addr)) { 499*7c478bd9Sstevel@tonic-gate proximity = SLP_SUBNET_PROX; 500*7c478bd9Sstevel@tonic-gate } else { 501*7c478bd9Sstevel@tonic-gate proximity = SLP_REMOTE_PROX; 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate /* 505*7c478bd9Sstevel@tonic-gate * sort the DAs into the entry list, ranked by the number of 506*7c478bd9Sstevel@tonic-gate * relevant scopes they serve (coverage). 507*7c478bd9Sstevel@tonic-gate */ 508*7c478bd9Sstevel@tonic-gate coverage = 0; 509*7c478bd9Sstevel@tonic-gate if (!(sscopes = slp_utf_strchr(surl->s_pcSrvPart, '='))) { 510*7c478bd9Sstevel@tonic-gate /* URL part should be of the form 'scopes=...' */ 511*7c478bd9Sstevel@tonic-gate goto cleanup; 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate sscopes++; 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate /* cut off host scope at end */ 516*7c478bd9Sstevel@tonic-gate if (sscopes_end = slp_utf_strchr(sscopes, '=')) { 517*7c478bd9Sstevel@tonic-gate /* skip the =[hostname] at the end */ 518*7c478bd9Sstevel@tonic-gate *sscopes_end = 0; 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* copy out the scopes part, since url will be freed after this call */ 522*7c478bd9Sstevel@tonic-gate if (!(sscopes = strdup(sscopes))) { 523*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "collect_DAs", "out of memory"); 524*7c478bd9Sstevel@tonic-gate free(surl); 525*7c478bd9Sstevel@tonic-gate return (SLP_FALSE); 526*7c478bd9Sstevel@tonic-gate } 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate for (s = tl->all_scopes; s; s = p) { 529*7c478bd9Sstevel@tonic-gate p = slp_utf_strchr(s, ','); 530*7c478bd9Sstevel@tonic-gate if (p) 531*7c478bd9Sstevel@tonic-gate *p = 0; 532*7c478bd9Sstevel@tonic-gate if (slp_onlist(s, sscopes)) { 533*7c478bd9Sstevel@tonic-gate /* add to uc list; remove from mc list */ 534*7c478bd9Sstevel@tonic-gate slp_add2list(s, &(tl->uc_scopes), SLP_TRUE); 535*7c478bd9Sstevel@tonic-gate slp_list_subtract(s, &(tl->mc_scopes)); 536*7c478bd9Sstevel@tonic-gate coverage++; 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate if (p) 539*7c478bd9Sstevel@tonic-gate *p++ = ','; 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate if (coverage) 542*7c478bd9Sstevel@tonic-gate add_da_entry(&(tl->DAs), sin, sscopes, proximity, coverage); 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate cleanup: 545*7c478bd9Sstevel@tonic-gate free(url); 546*7c478bd9Sstevel@tonic-gate if (surl) free(surl); 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate return (SLP_TRUE); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate /* 552*7c478bd9Sstevel@tonic-gate * Takes a scopes list of the form 's1,s2,s3,...' and formats it into 553*7c478bd9Sstevel@tonic-gate * an LDAP search filter of the form '(|(SCOPETAG=s1)(SCOPETAG=s2)...)'. 554*7c478bd9Sstevel@tonic-gate * 'scopes' contains the scopes list; 'q' is a buffer allocated 555*7c478bd9Sstevel@tonic-gate * by the caller into which the result will be placed. 556*7c478bd9Sstevel@tonic-gate */ 557*7c478bd9Sstevel@tonic-gate static void format_query(char *q, const char *scopes) { 558*7c478bd9Sstevel@tonic-gate char *p, *s; 559*7c478bd9Sstevel@tonic-gate int more_than_one = slp_utf_strchr(scopes, ',') ? 1 : 0; 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate *q++ = '('; *q++ = '&'; 562*7c478bd9Sstevel@tonic-gate if (more_than_one) { 563*7c478bd9Sstevel@tonic-gate *q++ = '('; *q++ = '|'; 564*7c478bd9Sstevel@tonic-gate } 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate for (p = s = (char *)scopes; p; s = p) { 567*7c478bd9Sstevel@tonic-gate *q++ = '('; 568*7c478bd9Sstevel@tonic-gate (void) strcpy(q, SLP_SUN_SCOPES_TAG); 569*7c478bd9Sstevel@tonic-gate q += strlen(SLP_SUN_SCOPES_TAG); 570*7c478bd9Sstevel@tonic-gate *q++ = '='; 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate p = slp_utf_strchr(s, ','); 573*7c478bd9Sstevel@tonic-gate if (p) { 574*7c478bd9Sstevel@tonic-gate (void) memcpy(q, s, p - s); 575*7c478bd9Sstevel@tonic-gate q += (p - s); 576*7c478bd9Sstevel@tonic-gate p++; 577*7c478bd9Sstevel@tonic-gate } else { 578*7c478bd9Sstevel@tonic-gate (void) strcpy(q, s); 579*7c478bd9Sstevel@tonic-gate q += strlen(s); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate *q++ = ')'; 582*7c478bd9Sstevel@tonic-gate } 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate if (more_than_one) { 585*7c478bd9Sstevel@tonic-gate *q++ = ')'; 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate *q++ = '('; 588*7c478bd9Sstevel@tonic-gate (void) strcpy(q, SLP_SUN_VERSION_TAG); 589*7c478bd9Sstevel@tonic-gate q += strlen(SLP_SUN_VERSION_TAG); 590*7c478bd9Sstevel@tonic-gate *q++ = '='; 591*7c478bd9Sstevel@tonic-gate *q++ = '2'; 592*7c478bd9Sstevel@tonic-gate *q++ = ')'; 593*7c478bd9Sstevel@tonic-gate *q++ = ')'; 594*7c478bd9Sstevel@tonic-gate *q = 0; 595*7c478bd9Sstevel@tonic-gate } 596