1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Just in case we're not in a build environment, make sure that 31*0Sstevel@tonic-gate * TEXT_DOMAIN gets set to something. 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 34*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 35*0Sstevel@tonic-gate #endif 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #include <meta.h> 38*0Sstevel@tonic-gate #include <metad.h> 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #define CC_TTL_MAX 20 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate typedef struct { 43*0Sstevel@tonic-gate char *cc_node; 44*0Sstevel@tonic-gate struct timeval cc_ttl; 45*0Sstevel@tonic-gate CLIENT *cc_clp; 46*0Sstevel@tonic-gate } client_cache_t; 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate typedef struct client_header { 49*0Sstevel@tonic-gate client_cache_t **ch_cache; /* array of clients. */ 50*0Sstevel@tonic-gate mutex_t ch_mutex; /* lock access to ch_cache */ 51*0Sstevel@tonic-gate } client_header_t; 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate /* 54*0Sstevel@tonic-gate * This structure is used to pass data from meta_client_create to 55*0Sstevel@tonic-gate * client_create_helper via meta_client_create_retry. 56*0Sstevel@tonic-gate */ 57*0Sstevel@tonic-gate typedef struct clnt_data { 58*0Sstevel@tonic-gate rpcprog_t cd_prognum; /* RPC program number */ 59*0Sstevel@tonic-gate rpcvers_t cd_version; /* Desired interface version */ 60*0Sstevel@tonic-gate char *cd_nettype; /* Type of network to use */ 61*0Sstevel@tonic-gate } clnt_data_t; 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #define MALLOC_BLK_SIZE 10 64*0Sstevel@tonic-gate static client_header_t client_header = {(client_cache_t **)NULL, DEFAULTMUTEX}; 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate static void 67*0Sstevel@tonic-gate cc_add( 68*0Sstevel@tonic-gate client_header_t *header, 69*0Sstevel@tonic-gate char *node, 70*0Sstevel@tonic-gate CLIENT *clntp, 71*0Sstevel@tonic-gate md_error_t *ep 72*0Sstevel@tonic-gate ) 73*0Sstevel@tonic-gate { 74*0Sstevel@tonic-gate client_cache_t ***cachep = &header->ch_cache; 75*0Sstevel@tonic-gate struct timeval now; 76*0Sstevel@tonic-gate int i; 77*0Sstevel@tonic-gate int j = 0; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate if (gettimeofday(&now, NULL) == -1) { 80*0Sstevel@tonic-gate (void) mdsyserror(ep, errno, "gettimeofday()"); 81*0Sstevel@tonic-gate return; 82*0Sstevel@tonic-gate } 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate (void) mutex_lock(&header->ch_mutex); 85*0Sstevel@tonic-gate if (*cachep) { 86*0Sstevel@tonic-gate for (i = 0; (*cachep)[i] != NULL; i++) 87*0Sstevel@tonic-gate if (strcmp((*cachep)[i]->cc_node, node) == 0 && 88*0Sstevel@tonic-gate (*cachep)[i]->cc_clp == NULL) { 89*0Sstevel@tonic-gate (*cachep)[i]->cc_clp = clntp; 90*0Sstevel@tonic-gate (*cachep)[i]->cc_ttl = now; 91*0Sstevel@tonic-gate (void) mutex_unlock(&header->ch_mutex); 92*0Sstevel@tonic-gate return; 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate } else { 95*0Sstevel@tonic-gate *cachep = Calloc(MALLOC_BLK_SIZE, sizeof (**cachep)); 96*0Sstevel@tonic-gate i = 0; 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate (*cachep)[i] = Zalloc(sizeof (***cachep)); 100*0Sstevel@tonic-gate (*cachep)[i]->cc_node = Strdup(node); 101*0Sstevel@tonic-gate (*cachep)[i]->cc_clp = clntp; 102*0Sstevel@tonic-gate (*cachep)[i]->cc_ttl = now; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate if ((++i % MALLOC_BLK_SIZE) == 0) { 105*0Sstevel@tonic-gate *cachep = Realloc(*cachep, 106*0Sstevel@tonic-gate (i + MALLOC_BLK_SIZE) * sizeof (**cachep)); 107*0Sstevel@tonic-gate for (j = i; j < (i + MALLOC_BLK_SIZE); j++) 108*0Sstevel@tonic-gate (*cachep)[j] = NULL; 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate (void) mutex_unlock(&header->ch_mutex); 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate static void 114*0Sstevel@tonic-gate rel_clntp(client_cache_t *cachep) 115*0Sstevel@tonic-gate { 116*0Sstevel@tonic-gate CLIENT *clntp = cachep->cc_clp; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate if (clntp != NULL) { 119*0Sstevel@tonic-gate auth_destroy(clntp->cl_auth); 120*0Sstevel@tonic-gate clnt_destroy(clntp); 121*0Sstevel@tonic-gate } 122*0Sstevel@tonic-gate cachep->cc_clp = NULL; 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate static void 126*0Sstevel@tonic-gate cc_destroy(client_header_t *header) 127*0Sstevel@tonic-gate { 128*0Sstevel@tonic-gate client_cache_t ***cachep = &header->ch_cache; 129*0Sstevel@tonic-gate int i; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate (void) mutex_lock(&header->ch_mutex); 132*0Sstevel@tonic-gate if (*cachep) { 133*0Sstevel@tonic-gate for (i = 0; ((*cachep)[i] != NULL); i++) { 134*0Sstevel@tonic-gate client_cache_t *p = (*cachep)[i]; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate Free(p->cc_node); 137*0Sstevel@tonic-gate rel_clntp(p); 138*0Sstevel@tonic-gate Free(p); 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate Free(*cachep); 141*0Sstevel@tonic-gate *cachep = NULL; 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate (void) mutex_unlock(&header->ch_mutex); 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* 147*0Sstevel@tonic-gate * Set the timeout value for this client handle. 148*0Sstevel@tonic-gate */ 149*0Sstevel@tonic-gate static int 150*0Sstevel@tonic-gate cl_sto( 151*0Sstevel@tonic-gate CLIENT *clntp, 152*0Sstevel@tonic-gate char *hostname, 153*0Sstevel@tonic-gate long time_out, 154*0Sstevel@tonic-gate md_error_t *ep 155*0Sstevel@tonic-gate ) 156*0Sstevel@tonic-gate { 157*0Sstevel@tonic-gate struct timeval nto; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate (void) memset(&nto, '\0', sizeof (nto)); 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate nto.tv_sec = time_out; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate if (clnt_control(clntp, CLSET_TIMEOUT, (char *)&nto) != TRUE) 164*0Sstevel@tonic-gate return (mdrpcerror(ep, clntp, hostname, 165*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "metad client set timeout"))); 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate return (0); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate /* 171*0Sstevel@tonic-gate * client_create_vers_retry is the helper function to be passed to 172*0Sstevel@tonic-gate * meta_client_create_retry to do the actual work of creating the client 173*0Sstevel@tonic-gate * when version selection is necessary. 174*0Sstevel@tonic-gate */ 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /* ARGSUSED */ 177*0Sstevel@tonic-gate static CLIENT * 178*0Sstevel@tonic-gate client_create_vers_retry(char *hostname, 179*0Sstevel@tonic-gate void *ignore, 180*0Sstevel@tonic-gate struct timeval *tout 181*0Sstevel@tonic-gate ) 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate rpcvers_t vers; /* Version # not needed. */ 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate return (clnt_create_vers_timed(hostname, METAD, &vers, 186*0Sstevel@tonic-gate METAD_VERSION, METAD_VERSION_DEVID, "tcp", tout)); 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate /* 190*0Sstevel@tonic-gate * client_create_helper is the helper function to be passed to 191*0Sstevel@tonic-gate * meta_client_create_retry when plain vanilla client create is desired. 192*0Sstevel@tonic-gate */ 193*0Sstevel@tonic-gate static CLIENT * 194*0Sstevel@tonic-gate client_create_helper(char *hostname, void *private, struct timeval *time_out) 195*0Sstevel@tonic-gate { 196*0Sstevel@tonic-gate clnt_data_t *cd = (clnt_data_t *)private; 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate return (clnt_create_timed(hostname, cd->cd_prognum, cd->cd_version, 199*0Sstevel@tonic-gate cd->cd_nettype, time_out)); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate /* 203*0Sstevel@tonic-gate * meta_client_create_retry is a general function to assist in creating RPC 204*0Sstevel@tonic-gate * clients. This function handles retrying if the attempt to create a 205*0Sstevel@tonic-gate * client fails. meta_client_create_retry itself does not actually create 206*0Sstevel@tonic-gate * the client. Instead it calls the helper function, func, to do that job. 207*0Sstevel@tonic-gate * 208*0Sstevel@tonic-gate * With the help of func, meta_client_create_retry will create an RPC 209*0Sstevel@tonic-gate * connection allowing up to tout seconds to complete the task. If the 210*0Sstevel@tonic-gate * connection creation fails for RPC_RPCBFAILURE, RPC_CANTRECV or 211*0Sstevel@tonic-gate * RPC_PROGNOTREGISTERED and tout seconds have not passed, 212*0Sstevel@tonic-gate * meta_client_create_retry will try again. The reason retries are 213*0Sstevel@tonic-gate * important is that when the inet daemon is being refreshed, it can take 214*0Sstevel@tonic-gate * 15-20 seconds for it to start responding again. 215*0Sstevel@tonic-gate * 216*0Sstevel@tonic-gate * Arguments: 217*0Sstevel@tonic-gate * 218*0Sstevel@tonic-gate * hostname - Name of remote host 219*0Sstevel@tonic-gate * 220*0Sstevel@tonic-gate * func - Pointer to the helper function, that will 221*0Sstevel@tonic-gate * actually try to create the client. 222*0Sstevel@tonic-gate * 223*0Sstevel@tonic-gate * data - Private data to be passed on to func. 224*0Sstevel@tonic-gate * meta_client_create_retry treats this as an opaque 225*0Sstevel@tonic-gate * pointer. 226*0Sstevel@tonic-gate * 227*0Sstevel@tonic-gate * tout - Number of seconds to allow for the connection 228*0Sstevel@tonic-gate * attempt. 229*0Sstevel@tonic-gate * 230*0Sstevel@tonic-gate * ep - Standard SVM error pointer. May be NULL. 231*0Sstevel@tonic-gate */ 232*0Sstevel@tonic-gate CLIENT * 233*0Sstevel@tonic-gate meta_client_create_retry( 234*0Sstevel@tonic-gate char *hostname, 235*0Sstevel@tonic-gate clnt_create_func_t func, 236*0Sstevel@tonic-gate void *data, 237*0Sstevel@tonic-gate time_t tout, 238*0Sstevel@tonic-gate md_error_t *ep 239*0Sstevel@tonic-gate ) 240*0Sstevel@tonic-gate { 241*0Sstevel@tonic-gate static int debug; /* print debugging info */ 242*0Sstevel@tonic-gate static int debug_set = 0; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate CLIENT *clnt = (CLIENT *) NULL; 245*0Sstevel@tonic-gate struct timeval curtime; 246*0Sstevel@tonic-gate char *d; 247*0Sstevel@tonic-gate struct timeval start; 248*0Sstevel@tonic-gate struct timeval timeout; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if (debug_set == 0) { 251*0Sstevel@tonic-gate d = getenv("MD_DEBUG"); 252*0Sstevel@tonic-gate if (d == NULL) { 253*0Sstevel@tonic-gate debug = 0; 254*0Sstevel@tonic-gate } else { 255*0Sstevel@tonic-gate debug = (strstr(d, "RPC") == NULL) ? 0 : 1; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate debug_set = 1; 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate timeout.tv_usec = 0; 260*0Sstevel@tonic-gate if (gettimeofday(&start, NULL) == -1) { 261*0Sstevel@tonic-gate if (ep != (md_error_t *)NULL) { 262*0Sstevel@tonic-gate (void) mdsyserror(ep, errno, "gettimeofday()"); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate return (clnt); 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate curtime = start; 267*0Sstevel@tonic-gate while ((curtime.tv_sec - start.tv_sec) < tout) { 268*0Sstevel@tonic-gate /* Use remaining time as the timeout value. */ 269*0Sstevel@tonic-gate timeout.tv_sec = tout - (curtime.tv_sec - start.tv_sec); 270*0Sstevel@tonic-gate clnt = (*func)(hostname, data, &timeout); 271*0Sstevel@tonic-gate if (clnt != (CLIENT *) NULL) 272*0Sstevel@tonic-gate break; 273*0Sstevel@tonic-gate if ((rpc_createerr.cf_stat == RPC_RPCBFAILURE) || 274*0Sstevel@tonic-gate (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) || 275*0Sstevel@tonic-gate (rpc_createerr.cf_stat == RPC_CANTRECV)) { 276*0Sstevel@tonic-gate if (debug) { 277*0Sstevel@tonic-gate clnt_pcreateerror("meta_client_create_retry"); 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate /* If error might be fixed in time, sleep & try again */ 280*0Sstevel@tonic-gate (void) sleep(2); 281*0Sstevel@tonic-gate if (gettimeofday(&curtime, NULL) == -1) { 282*0Sstevel@tonic-gate if (ep != (md_error_t *)NULL) { 283*0Sstevel@tonic-gate (void) mdsyserror(ep, errno, 284*0Sstevel@tonic-gate "gettimeofday()"); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate return (clnt); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate } else { 289*0Sstevel@tonic-gate /* Not a recoverable error. */ 290*0Sstevel@tonic-gate break; 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate if ((clnt == (CLIENT *) NULL) && (ep != (md_error_t *)NULL)) { 294*0Sstevel@tonic-gate (void) mdrpccreateerror(ep, hostname, 295*0Sstevel@tonic-gate "meta_client_create_retry"); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate return (clnt); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * meta_client_create is intended to be used within SVM as a replacement 302*0Sstevel@tonic-gate * for calls to clnt_create. meta_client_create invokes the retry 303*0Sstevel@tonic-gate * mechanism of meta_client_create_retry. 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate CLIENT * 306*0Sstevel@tonic-gate meta_client_create(char *host, rpcprog_t prognum, rpcvers_t version, 307*0Sstevel@tonic-gate char *nettype) 308*0Sstevel@tonic-gate { 309*0Sstevel@tonic-gate clnt_data_t cd; 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate cd.cd_prognum = prognum; 312*0Sstevel@tonic-gate cd.cd_version = version; 313*0Sstevel@tonic-gate cd.cd_nettype = nettype; 314*0Sstevel@tonic-gate return (meta_client_create_retry(host, client_create_helper, 315*0Sstevel@tonic-gate (void *)&cd, MD_CLNT_CREATE_TOUT, (md_error_t *)NULL)); 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate /* 319*0Sstevel@tonic-gate * create and return RPC connection 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate CLIENT * 322*0Sstevel@tonic-gate metarpcopen( 323*0Sstevel@tonic-gate char *hostname, 324*0Sstevel@tonic-gate long time_out, 325*0Sstevel@tonic-gate md_error_t *ep 326*0Sstevel@tonic-gate ) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate CLIENT *clntp = NULL; 329*0Sstevel@tonic-gate client_cache_t ***cachep = &client_header.ch_cache; 330*0Sstevel@tonic-gate int i; 331*0Sstevel@tonic-gate long delta; 332*0Sstevel@tonic-gate struct timeval now; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate if (gettimeofday(&now, NULL) == -1) { 335*0Sstevel@tonic-gate (void) mdsyserror(ep, errno, "gettimeofday()"); 336*0Sstevel@tonic-gate return (NULL); 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate /* 340*0Sstevel@tonic-gate * Before trying to create the client, make sure that the core SVM 341*0Sstevel@tonic-gate * services are enabled by the Service Management Facility. We 342*0Sstevel@tonic-gate * don't want to suffer the 60 second timeout if the services are 343*0Sstevel@tonic-gate * not even enabled. This call actually only verifies that they 344*0Sstevel@tonic-gate * are enabled on this host no matter which host the caller wants 345*0Sstevel@tonic-gate * to connect to. Nonetheless, if the services are not enabled on 346*0Sstevel@tonic-gate * the local host, our RPC stuff is not going to work as expected. 347*0Sstevel@tonic-gate */ 348*0Sstevel@tonic-gate if (meta_smf_isonline(META_SMF_CORE, ep) == 0) { 349*0Sstevel@tonic-gate return (NULL); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate (void) mutex_lock(&client_header.ch_mutex); 353*0Sstevel@tonic-gate if (client_header.ch_cache) { 354*0Sstevel@tonic-gate for (i = 0; (*cachep)[i] != NULL; i++) { 355*0Sstevel@tonic-gate if (strcmp((*cachep)[i]->cc_node, hostname) == 0) { 356*0Sstevel@tonic-gate clntp = (*cachep)[i]->cc_clp; 357*0Sstevel@tonic-gate if (clntp == NULL) 358*0Sstevel@tonic-gate continue; 359*0Sstevel@tonic-gate delta = now.tv_sec - 360*0Sstevel@tonic-gate (*cachep)[i]->cc_ttl.tv_sec; 361*0Sstevel@tonic-gate if (delta > CC_TTL_MAX) { 362*0Sstevel@tonic-gate rel_clntp((*cachep)[i]); 363*0Sstevel@tonic-gate continue; 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate if (cl_sto(clntp, hostname, time_out, 366*0Sstevel@tonic-gate ep) != 0) { 367*0Sstevel@tonic-gate (void) mutex_unlock( 368*0Sstevel@tonic-gate &client_header.ch_mutex); 369*0Sstevel@tonic-gate return (NULL); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate (void) mutex_unlock(&client_header.ch_mutex); 372*0Sstevel@tonic-gate return (clntp); 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate } 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate (void) mutex_unlock(&client_header.ch_mutex); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate /* 379*0Sstevel@tonic-gate * Try to create a version 2 client handle by default. 380*0Sstevel@tonic-gate * If this fails (i.e. client is version 1), try to 381*0Sstevel@tonic-gate * create a version 1 client handle. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate clntp = meta_client_create_retry(hostname, client_create_vers_retry, 384*0Sstevel@tonic-gate (void *)NULL, MD_CLNT_CREATE_TOUT, ep); 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* open connection */ 387*0Sstevel@tonic-gate if (clntp == NULL) { 388*0Sstevel@tonic-gate (void) mdrpccreateerror(ep, hostname, 389*0Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "metad client create")); 390*0Sstevel@tonic-gate cc_add(&client_header, hostname, NULL, ep); 391*0Sstevel@tonic-gate return (NULL); 392*0Sstevel@tonic-gate } else { 393*0Sstevel@tonic-gate auth_destroy(clntp->cl_auth); 394*0Sstevel@tonic-gate clntp->cl_auth = authsys_create_default(); 395*0Sstevel@tonic-gate assert(clntp->cl_auth != NULL); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate cc_add(&client_header, hostname, clntp, ep); 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate if (cl_sto(clntp, hostname, time_out, ep) != 0) 401*0Sstevel@tonic-gate return (NULL); 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate return (clntp); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate /* 407*0Sstevel@tonic-gate * metarpcclose - is a place holder so that when using 408*0Sstevel@tonic-gate * metarpcopen, it does not appear that 409*0Sstevel@tonic-gate * we have dangling opens. We can at some 410*0Sstevel@tonic-gate * later decrement open counts here too, if needed. 411*0Sstevel@tonic-gate */ 412*0Sstevel@tonic-gate /*ARGSUSED*/ 413*0Sstevel@tonic-gate void 414*0Sstevel@tonic-gate metarpcclose(CLIENT *clntp) 415*0Sstevel@tonic-gate { 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate void 419*0Sstevel@tonic-gate metarpccloseall(void) 420*0Sstevel@tonic-gate { 421*0Sstevel@tonic-gate cc_destroy(&client_header); 422*0Sstevel@tonic-gate } 423