1 1.33 christos /* $NetBSD: clnt_generic.c,v 1.33 2014/05/28 14:45:19 christos Exp $ */ 2 1.4 cgd 3 1.1 cgd /* 4 1.30 tron * Copyright (c) 2010, Oracle America, Inc. 5 1.30 tron * 6 1.30 tron * Redistribution and use in source and binary forms, with or without 7 1.30 tron * modification, are permitted provided that the following conditions are 8 1.30 tron * met: 9 1.30 tron * 10 1.30 tron * * Redistributions of source code must retain the above copyright 11 1.30 tron * notice, this list of conditions and the following disclaimer. 12 1.30 tron * * Redistributions in binary form must reproduce the above 13 1.30 tron * copyright notice, this list of conditions and the following 14 1.30 tron * disclaimer in the documentation and/or other materials 15 1.30 tron * provided with the distribution. 16 1.30 tron * * Neither the name of the "Oracle America, Inc." nor the names of its 17 1.30 tron * contributors may be used to endorse or promote products derived 18 1.30 tron * from this software without specific prior written permission. 19 1.30 tron * 20 1.30 tron * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 1.30 tron * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 1.30 tron * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 1.30 tron * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 1.30 tron * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 1.30 tron * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.30 tron * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 1.30 tron * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.30 tron * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 1.30 tron * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 1.30 tron * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 1.30 tron * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 cgd */ 33 1.16 fvdl /* 34 1.16 fvdl * Copyright (c) 1986-1991 by Sun Microsystems Inc. 35 1.16 fvdl */ 36 1.16 fvdl 37 1.16 fvdl /* #ident "@(#)clnt_generic.c 1.20 94/05/03 SMI" */ 38 1.1 cgd 39 1.22 itojun #include <sys/cdefs.h> 40 1.22 itojun #if defined(LIBC_SCCS) && !defined(lint) 41 1.7 christos #if 0 42 1.16 fvdl static char sccsid[] = "@(#)clnt_generic.c 1.32 89/03/16 Copyr 1988 Sun Micro"; 43 1.22 itojun #else 44 1.33 christos __RCSID("$NetBSD: clnt_generic.c,v 1.33 2014/05/28 14:45:19 christos Exp $"); 45 1.7 christos #endif 46 1.1 cgd #endif 47 1.1 cgd 48 1.8 jtc #include "namespace.h" 49 1.16 fvdl #include "reentrant.h" 50 1.11 lukem #include <sys/types.h> 51 1.11 lukem #include <sys/socket.h> 52 1.16 fvdl #include <netinet/in.h> 53 1.19 lukem #include <assert.h> 54 1.16 fvdl #include <stdio.h> 55 1.11 lukem #include <errno.h> 56 1.16 fvdl #include <rpc/rpc.h> 57 1.18 christos #include <rpc/nettype.h> 58 1.10 lukem #include <string.h> 59 1.16 fvdl #include <stdlib.h> 60 1.16 fvdl #include <unistd.h> 61 1.29 christos 62 1.29 christos #include "svc_fdset.h" 63 1.20 fvdl #include "rpc_internal.h" 64 1.8 jtc 65 1.8 jtc #ifdef __weak_alias 66 1.16 fvdl __weak_alias(clnt_create_vers,_clnt_create_vers) 67 1.15 mycroft __weak_alias(clnt_create,_clnt_create) 68 1.16 fvdl __weak_alias(clnt_tp_create,_clnt_tp_create) 69 1.16 fvdl __weak_alias(clnt_tli_create,_clnt_tli_create) 70 1.8 jtc #endif 71 1.1 cgd 72 1.1 cgd /* 73 1.16 fvdl * Generic client creation with version checking the value of 74 1.16 fvdl * vers_out is set to the highest server supported value 75 1.16 fvdl * vers_low <= vers_out <= vers_high AND an error results 76 1.16 fvdl * if this can not be done. 77 1.16 fvdl */ 78 1.16 fvdl CLIENT * 79 1.28 matt clnt_create_vers( 80 1.28 matt const char * hostname, 81 1.28 matt rpcprog_t prog, 82 1.28 matt rpcvers_t * vers_out, 83 1.28 matt rpcvers_t vers_low, 84 1.28 matt rpcvers_t vers_high, 85 1.28 matt const char * nettype) 86 1.16 fvdl { 87 1.16 fvdl CLIENT *clnt; 88 1.16 fvdl struct timeval to; 89 1.16 fvdl enum clnt_stat rpc_stat; 90 1.16 fvdl struct rpc_err rpcerr; 91 1.16 fvdl 92 1.19 lukem _DIAGASSERT(hostname != NULL); 93 1.19 lukem _DIAGASSERT(vers_out != NULL); 94 1.19 lukem /* XXX: nettype appears to support being NULL */ 95 1.19 lukem 96 1.16 fvdl clnt = clnt_create(hostname, prog, vers_high, nettype); 97 1.16 fvdl if (clnt == NULL) { 98 1.16 fvdl return (NULL); 99 1.16 fvdl } 100 1.16 fvdl to.tv_sec = 10; 101 1.16 fvdl to.tv_usec = 0; 102 1.16 fvdl rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, 103 1.27 christos NULL, (xdrproc_t) xdr_void, NULL, to); 104 1.16 fvdl if (rpc_stat == RPC_SUCCESS) { 105 1.16 fvdl *vers_out = vers_high; 106 1.16 fvdl return (clnt); 107 1.16 fvdl } 108 1.16 fvdl if (rpc_stat == RPC_PROGVERSMISMATCH) { 109 1.16 fvdl unsigned long minvers, maxvers; 110 1.16 fvdl 111 1.16 fvdl clnt_geterr(clnt, &rpcerr); 112 1.16 fvdl minvers = rpcerr.re_vers.low; 113 1.16 fvdl maxvers = rpcerr.re_vers.high; 114 1.16 fvdl if (maxvers < vers_high) 115 1.18 christos vers_high = (rpcvers_t)maxvers; 116 1.16 fvdl if (minvers > vers_low) 117 1.18 christos vers_low = (rpcvers_t)minvers; 118 1.16 fvdl if (vers_low > vers_high) { 119 1.16 fvdl goto error; 120 1.16 fvdl } 121 1.18 christos CLNT_CONTROL(clnt, CLSET_VERS, (char *)(void *)&vers_high); 122 1.16 fvdl rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, 123 1.27 christos NULL, (xdrproc_t) xdr_void, NULL, to); 124 1.16 fvdl if (rpc_stat == RPC_SUCCESS) { 125 1.16 fvdl *vers_out = vers_high; 126 1.16 fvdl return (clnt); 127 1.16 fvdl } 128 1.16 fvdl } 129 1.16 fvdl clnt_geterr(clnt, &rpcerr); 130 1.16 fvdl 131 1.16 fvdl error: 132 1.16 fvdl rpc_createerr.cf_stat = rpc_stat; 133 1.16 fvdl rpc_createerr.cf_error = rpcerr; 134 1.16 fvdl clnt_destroy(clnt); 135 1.16 fvdl return (NULL); 136 1.16 fvdl } 137 1.16 fvdl 138 1.16 fvdl /* 139 1.16 fvdl * Top level client creation routine. 140 1.16 fvdl * Generic client creation: takes (servers name, program-number, nettype) and 141 1.16 fvdl * returns client handle. Default options are set, which the user can 142 1.1 cgd * change using the rpc equivalent of ioctl()'s. 143 1.16 fvdl * 144 1.16 fvdl * It tries for all the netids in that particular class of netid until 145 1.16 fvdl * it succeeds. 146 1.16 fvdl * XXX The error message in the case of failure will be the one 147 1.16 fvdl * pertaining to the last create error. 148 1.16 fvdl * 149 1.16 fvdl * It calls clnt_tp_create(); 150 1.1 cgd */ 151 1.1 cgd CLIENT * 152 1.28 matt clnt_create( 153 1.28 matt const char * hostname, /* server name */ 154 1.28 matt rpcprog_t prog, /* program number */ 155 1.28 matt rpcvers_t vers, /* version number */ 156 1.28 matt const char * nettype) /* net type */ 157 1.1 cgd { 158 1.16 fvdl struct netconfig *nconf; 159 1.16 fvdl CLIENT *clnt = NULL; 160 1.16 fvdl void *handle; 161 1.16 fvdl enum clnt_stat save_cf_stat = RPC_SUCCESS; 162 1.16 fvdl struct rpc_err save_cf_error; 163 1.16 fvdl 164 1.19 lukem _DIAGASSERT(hostname != NULL); 165 1.19 lukem /* XXX: nettype appears to support being NULL */ 166 1.16 fvdl 167 1.18 christos if ((handle = __rpc_setconf(nettype)) == NULL) { 168 1.16 fvdl rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 169 1.18 christos return (NULL); 170 1.16 fvdl } 171 1.16 fvdl rpc_createerr.cf_stat = RPC_SUCCESS; 172 1.18 christos while (clnt == NULL) { 173 1.16 fvdl if ((nconf = __rpc_getconf(handle)) == NULL) { 174 1.16 fvdl if (rpc_createerr.cf_stat == RPC_SUCCESS) 175 1.16 fvdl rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 176 1.16 fvdl break; 177 1.16 fvdl } 178 1.16 fvdl #ifdef CLNT_DEBUG 179 1.16 fvdl printf("trying netid %s\n", nconf->nc_netid); 180 1.16 fvdl #endif 181 1.16 fvdl clnt = clnt_tp_create(hostname, prog, vers, nconf); 182 1.16 fvdl if (clnt) 183 1.16 fvdl break; 184 1.16 fvdl else 185 1.16 fvdl /* 186 1.16 fvdl * Since we didn't get a name-to-address 187 1.16 fvdl * translation failure here, we remember 188 1.16 fvdl * this particular error. The object of 189 1.16 fvdl * this is to enable us to return to the 190 1.16 fvdl * caller a more-specific error than the 191 1.16 fvdl * unhelpful ``Name to address translation 192 1.16 fvdl * failed'' which might well occur if we 193 1.16 fvdl * merely returned the last error (because 194 1.16 fvdl * the local loopbacks are typically the 195 1.16 fvdl * last ones in /etc/netconfig and the most 196 1.16 fvdl * likely to be unable to translate a host 197 1.16 fvdl * name). 198 1.16 fvdl */ 199 1.16 fvdl if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE) { 200 1.16 fvdl save_cf_stat = rpc_createerr.cf_stat; 201 1.16 fvdl save_cf_error = rpc_createerr.cf_error; 202 1.16 fvdl } 203 1.1 cgd } 204 1.16 fvdl 205 1.16 fvdl /* 206 1.16 fvdl * Attempt to return an error more specific than ``Name to address 207 1.16 fvdl * translation failed'' 208 1.16 fvdl */ 209 1.16 fvdl if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE) && 210 1.16 fvdl (save_cf_stat != RPC_SUCCESS)) { 211 1.16 fvdl rpc_createerr.cf_stat = save_cf_stat; 212 1.16 fvdl rpc_createerr.cf_error = save_cf_error; 213 1.1 cgd } 214 1.16 fvdl __rpc_endconf(handle); 215 1.16 fvdl return (clnt); 216 1.16 fvdl } 217 1.16 fvdl 218 1.16 fvdl /* 219 1.16 fvdl * Generic client creation: takes (servers name, program-number, netconf) and 220 1.16 fvdl * returns client handle. Default options are set, which the user can 221 1.16 fvdl * change using the rpc equivalent of ioctl()'s : clnt_control() 222 1.16 fvdl * It finds out the server address from rpcbind and calls clnt_tli_create() 223 1.16 fvdl */ 224 1.16 fvdl CLIENT * 225 1.28 matt clnt_tp_create( 226 1.28 matt const char * hostname, /* server name */ 227 1.28 matt rpcprog_t prog, /* program number */ 228 1.28 matt rpcvers_t vers, /* version number */ 229 1.28 matt const struct netconfig *nconf) /* net config struct */ 230 1.16 fvdl { 231 1.16 fvdl struct netbuf *svcaddr; /* servers address */ 232 1.16 fvdl CLIENT *cl = NULL; /* client handle */ 233 1.16 fvdl 234 1.19 lukem _DIAGASSERT(hostname != NULL); 235 1.19 lukem /* nconf is handled below */ 236 1.19 lukem 237 1.18 christos if (nconf == NULL) { 238 1.1 cgd rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 239 1.18 christos return (NULL); 240 1.16 fvdl } 241 1.16 fvdl 242 1.16 fvdl /* 243 1.16 fvdl * Get the address of the server 244 1.16 fvdl */ 245 1.16 fvdl if ((svcaddr = __rpcb_findaddr(prog, vers, nconf, hostname, 246 1.16 fvdl &cl)) == NULL) { 247 1.16 fvdl /* appropriate error number is set by rpcbind libraries */ 248 1.18 christos return (NULL); 249 1.16 fvdl } 250 1.18 christos if (cl == NULL) { 251 1.16 fvdl cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 252 1.16 fvdl prog, vers, 0, 0); 253 1.16 fvdl } else { 254 1.16 fvdl /* Reuse the CLIENT handle and change the appropriate fields */ 255 1.16 fvdl if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) { 256 1.27 christos if (cl->cl_netid == NULL) { 257 1.16 fvdl cl->cl_netid = strdup(nconf->nc_netid); 258 1.27 christos if (cl->cl_netid == NULL) 259 1.27 christos goto out; 260 1.27 christos } 261 1.27 christos if (cl->cl_tp == NULL) { 262 1.16 fvdl cl->cl_tp = strdup(nconf->nc_device); 263 1.27 christos if (cl->cl_tp == NULL) 264 1.27 christos goto out; 265 1.27 christos } 266 1.16 fvdl (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog); 267 1.16 fvdl (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers); 268 1.16 fvdl } else { 269 1.16 fvdl CLNT_DESTROY(cl); 270 1.16 fvdl cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 271 1.16 fvdl prog, vers, 0, 0); 272 1.16 fvdl } 273 1.1 cgd } 274 1.16 fvdl free(svcaddr->buf); 275 1.16 fvdl free(svcaddr); 276 1.16 fvdl return (cl); 277 1.27 christos out: 278 1.27 christos clnt_destroy(cl); 279 1.27 christos return NULL; 280 1.16 fvdl } 281 1.16 fvdl 282 1.16 fvdl /* 283 1.16 fvdl * Generic client creation: returns client handle. 284 1.16 fvdl * Default options are set, which the user can 285 1.16 fvdl * change using the rpc equivalent of ioctl()'s : clnt_control(). 286 1.16 fvdl * If fd is RPC_ANYFD, it will be opened using nconf. 287 1.16 fvdl * It will be bound if not so. 288 1.16 fvdl * If sizes are 0; appropriate defaults will be chosen. 289 1.16 fvdl */ 290 1.16 fvdl CLIENT * 291 1.28 matt clnt_tli_create( 292 1.28 matt int fd, /* fd */ 293 1.28 matt const struct netconfig *nconf, /* netconfig structure */ 294 1.28 matt const struct netbuf *svcaddr, /* servers address */ 295 1.28 matt rpcprog_t prog, /* program number */ 296 1.28 matt rpcvers_t vers, /* version number */ 297 1.28 matt u_int sendsz, /* send size */ 298 1.28 matt u_int recvsz) /* recv size */ 299 1.16 fvdl { 300 1.16 fvdl CLIENT *cl; /* client handle */ 301 1.16 fvdl bool_t madefd = FALSE; /* whether fd opened here */ 302 1.16 fvdl long servtype; 303 1.16 fvdl struct __rpc_sockinfo si; 304 1.19 lukem 305 1.19 lukem /* nconf is handled below */ 306 1.19 lukem _DIAGASSERT(svcaddr != NULL); 307 1.16 fvdl 308 1.16 fvdl if (fd == RPC_ANYFD) { 309 1.18 christos if (nconf == NULL) { 310 1.16 fvdl rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 311 1.18 christos return (NULL); 312 1.1 cgd } 313 1.16 fvdl 314 1.16 fvdl fd = __rpc_nconf2fd(nconf); 315 1.16 fvdl 316 1.16 fvdl if (fd == -1) 317 1.16 fvdl goto err; 318 1.16 fvdl 319 1.16 fvdl madefd = TRUE; 320 1.16 fvdl servtype = nconf->nc_semantics; 321 1.16 fvdl if (!__rpc_fd2sockinfo(fd, &si)) 322 1.16 fvdl goto err; 323 1.17 fvdl 324 1.32 christos (void)bindresvport(fd, NULL); 325 1.16 fvdl } else { 326 1.16 fvdl if (!__rpc_fd2sockinfo(fd, &si)) 327 1.16 fvdl goto err; 328 1.16 fvdl servtype = __rpc_socktype2seman(si.si_socktype); 329 1.16 fvdl if (servtype == -1) { 330 1.16 fvdl rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 331 1.16 fvdl return NULL; 332 1.16 fvdl } 333 1.16 fvdl 334 1.16 fvdl } 335 1.16 fvdl 336 1.16 fvdl if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { 337 1.16 fvdl rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */ 338 1.16 fvdl goto err1; 339 1.16 fvdl } 340 1.16 fvdl 341 1.16 fvdl switch (servtype) { 342 1.16 fvdl case NC_TPI_COTS_ORD: 343 1.16 fvdl cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); 344 1.16 fvdl if (!nconf || !cl) 345 1.16 fvdl break; 346 1.33 christos (void)__rpc_setnodelay(fd, &si); 347 1.1 cgd break; 348 1.16 fvdl case NC_TPI_CLTS: 349 1.16 fvdl cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); 350 1.1 cgd break; 351 1.1 cgd default: 352 1.16 fvdl goto err; 353 1.16 fvdl } 354 1.16 fvdl 355 1.18 christos if (cl == NULL) 356 1.16 fvdl goto err1; /* borrow errors from clnt_dg/vc creates */ 357 1.16 fvdl if (nconf) { 358 1.16 fvdl cl->cl_netid = strdup(nconf->nc_netid); 359 1.27 christos if (cl->cl_netid == NULL) 360 1.27 christos goto err0; 361 1.16 fvdl cl->cl_tp = strdup(nconf->nc_device); 362 1.27 christos if (cl->cl_tp == NULL) 363 1.27 christos goto err0; 364 1.16 fvdl } else { 365 1.25 yamt cl->cl_netid = __UNCONST(""); 366 1.25 yamt cl->cl_tp = __UNCONST(""); 367 1.1 cgd } 368 1.16 fvdl if (madefd) { 369 1.18 christos (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); 370 1.27 christos /* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ 371 1.16 fvdl }; 372 1.16 fvdl 373 1.16 fvdl return (cl); 374 1.16 fvdl 375 1.27 christos err0: 376 1.27 christos clnt_destroy(cl); 377 1.16 fvdl err: 378 1.16 fvdl rpc_createerr.cf_stat = RPC_SYSTEMERROR; 379 1.16 fvdl rpc_createerr.cf_error.re_errno = errno; 380 1.16 fvdl err1: if (madefd) 381 1.16 fvdl (void) close(fd); 382 1.18 christos return (NULL); 383 1.1 cgd } 384 1.31 christos 385 1.31 christos /* 386 1.31 christos * Don't block thse so interactive programs don't get stuck in lalaland. 387 1.31 christos * (easier to do this than making connect(2) non-blocking..) 388 1.31 christos */ 389 1.31 christos int 390 1.31 christos __clnt_sigfillset(sigset_t *ss) { 391 1.31 christos static const int usersig[] = { 392 1.31 christos SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP 393 1.31 christos }; 394 1.31 christos if (sigfillset(ss) == -1) 395 1.31 christos return -1; 396 1.31 christos for (size_t i = 0; i < __arraycount(usersig); i++) 397 1.31 christos if (sigdelset(ss, usersig[i]) == -1) 398 1.31 christos return -1; 399 1.31 christos return 0; 400 1.31 christos } 401