1 1.24 christos /* $NetBSD: rpc_soc.c,v 1.24 2024/01/23 17:24:38 christos Exp $ */ 2 1.1 fvdl 3 1.1 fvdl /* 4 1.18 tron * Copyright (c) 2010, Oracle America, Inc. 5 1.18 tron * 6 1.18 tron * Redistribution and use in source and binary forms, with or without 7 1.18 tron * modification, are permitted provided that the following conditions are 8 1.18 tron * met: 9 1.18 tron * 10 1.18 tron * * Redistributions of source code must retain the above copyright 11 1.18 tron * notice, this list of conditions and the following disclaimer. 12 1.18 tron * * Redistributions in binary form must reproduce the above 13 1.18 tron * copyright notice, this list of conditions and the following 14 1.18 tron * disclaimer in the documentation and/or other materials 15 1.18 tron * provided with the distribution. 16 1.18 tron * * Neither the name of the "Oracle America, Inc." nor the names of its 17 1.18 tron * contributors may be used to endorse or promote products derived 18 1.18 tron * from this software without specific prior written permission. 19 1.18 tron * 20 1.18 tron * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 1.18 tron * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 1.18 tron * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 1.18 tron * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 1.18 tron * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 1.18 tron * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.18 tron * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 1.18 tron * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.18 tron * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 1.18 tron * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 1.18 tron * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 1.18 tron * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 fvdl */ 33 1.1 fvdl 34 1.1 fvdl /* #ident "@(#)rpc_soc.c 1.17 94/04/24 SMI" */ 35 1.1 fvdl 36 1.1 fvdl /* 37 1.1 fvdl * Copyright (c) 1986-1991 by Sun Microsystems Inc. 38 1.1 fvdl * In addition, portions of such source code were derived from Berkeley 39 1.1 fvdl * 4.3 BSD under license from the Regents of the University of 40 1.1 fvdl * California. 41 1.1 fvdl */ 42 1.1 fvdl 43 1.11 itojun #include <sys/cdefs.h> 44 1.11 itojun #if defined(LIBC_SCCS) && !defined(lint) 45 1.1 fvdl #if 0 46 1.1 fvdl static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro"; 47 1.11 itojun #else 48 1.24 christos __RCSID("$NetBSD: rpc_soc.c,v 1.24 2024/01/23 17:24:38 christos Exp $"); 49 1.1 fvdl #endif 50 1.1 fvdl #endif 51 1.1 fvdl 52 1.1 fvdl #ifdef PORTMAP 53 1.1 fvdl /* 54 1.1 fvdl * rpc_soc.c 55 1.1 fvdl * 56 1.1 fvdl * The backward compatibility routines for the earlier implementation 57 1.1 fvdl * of RPC, where the only transports supported were tcp/ip and udp/ip. 58 1.1 fvdl * Based on berkeley socket abstraction, now implemented on the top 59 1.1 fvdl * of TLI/Streams 60 1.1 fvdl */ 61 1.1 fvdl 62 1.1 fvdl #include "namespace.h" 63 1.1 fvdl #include "reentrant.h" 64 1.1 fvdl #include <sys/types.h> 65 1.1 fvdl #include <sys/socket.h> 66 1.1 fvdl #include <stdio.h> 67 1.1 fvdl #include <rpc/rpc.h> 68 1.1 fvdl #include <rpc/pmap_clnt.h> 69 1.1 fvdl #include <rpc/pmap_prot.h> 70 1.6 christos #include <rpc/nettype.h> 71 1.1 fvdl #include <netinet/in.h> 72 1.7 lukem #include <assert.h> 73 1.7 lukem #include <errno.h> 74 1.1 fvdl #include <netdb.h> 75 1.1 fvdl #include <stdlib.h> 76 1.4 thorpej #include <string.h> 77 1.7 lukem #include <syslog.h> 78 1.1 fvdl #include <unistd.h> 79 1.1 fvdl 80 1.17 christos #include "svc_fdset.h" 81 1.9 fvdl #include "rpc_internal.h" 82 1.1 fvdl 83 1.1 fvdl #ifdef __weak_alias 84 1.1 fvdl __weak_alias(clntudp_bufcreate,_clntudp_bufcreate) 85 1.1 fvdl __weak_alias(clntudp_create,_clntudp_create) 86 1.1 fvdl __weak_alias(clnttcp_create,_clnttcp_create) 87 1.1 fvdl __weak_alias(clntraw_create,_clntraw_create) 88 1.1 fvdl __weak_alias(get_myaddress,_get_myaddress) 89 1.3 fvdl __weak_alias(svcfd_create,_svcfd_create) 90 1.2 fvdl __weak_alias(svcudp_bufcreate,_svcudp_bufcreate) 91 1.1 fvdl __weak_alias(svcudp_create,_svcudp_create) 92 1.1 fvdl __weak_alias(svctcp_create,_svctcp_create) 93 1.1 fvdl __weak_alias(svcraw_create,_svcraw_create) 94 1.1 fvdl __weak_alias(callrpc,_callrpc) 95 1.1 fvdl __weak_alias(registerrpc,_registerrpc) 96 1.1 fvdl __weak_alias(clnt_broadcast,_clnt_broadcast) 97 1.1 fvdl #endif 98 1.1 fvdl 99 1.14 matt static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t, 100 1.14 matt int *, u_int, u_int, const char *); 101 1.14 matt static SVCXPRT *svc_com_create(int, u_int, u_int, const char *); 102 1.14 matt static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *); 103 1.1 fvdl 104 1.1 fvdl /* 105 1.1 fvdl * A common clnt create routine 106 1.1 fvdl */ 107 1.1 fvdl static CLIENT * 108 1.14 matt clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, 109 1.14 matt int *sockp, u_int sendsz, u_int recvsz, const char *tp) 110 1.1 fvdl { 111 1.1 fvdl CLIENT *cl; 112 1.1 fvdl int madefd = FALSE; 113 1.7 lukem int fd; 114 1.1 fvdl struct netconfig *nconf; 115 1.1 fvdl struct netbuf bindaddr; 116 1.1 fvdl 117 1.7 lukem _DIAGASSERT(raddr != NULL); 118 1.7 lukem _DIAGASSERT(sockp != NULL); 119 1.7 lukem _DIAGASSERT(tp != NULL); 120 1.7 lukem 121 1.7 lukem fd = *sockp; 122 1.7 lukem 123 1.1 fvdl mutex_lock(&rpcsoc_lock); 124 1.1 fvdl if ((nconf = __rpc_getconfip(tp)) == NULL) { 125 1.1 fvdl rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 126 1.1 fvdl mutex_unlock(&rpcsoc_lock); 127 1.6 christos return (NULL); 128 1.1 fvdl } 129 1.1 fvdl if (fd == RPC_ANYSOCK) { 130 1.1 fvdl fd = __rpc_nconf2fd(nconf); 131 1.1 fvdl if (fd == -1) 132 1.1 fvdl goto syserror; 133 1.1 fvdl madefd = TRUE; 134 1.1 fvdl } 135 1.1 fvdl 136 1.1 fvdl if (raddr->sin_port == 0) { 137 1.1 fvdl u_int proto; 138 1.1 fvdl u_short sport; 139 1.1 fvdl 140 1.1 fvdl mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ 141 1.1 fvdl proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; 142 1.6 christos sport = pmap_getport(raddr, (u_long)prog, (u_long)vers, 143 1.6 christos proto); 144 1.1 fvdl if (sport == 0) { 145 1.1 fvdl goto err; 146 1.1 fvdl } 147 1.1 fvdl raddr->sin_port = htons(sport); 148 1.1 fvdl mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ 149 1.1 fvdl } 150 1.1 fvdl 151 1.1 fvdl /* Transform sockaddr_in to netbuf */ 152 1.1 fvdl bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); 153 1.1 fvdl bindaddr.buf = raddr; 154 1.1 fvdl 155 1.19 christos (void)bindresvport(fd, NULL); 156 1.1 fvdl cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, 157 1.1 fvdl sendsz, recvsz); 158 1.1 fvdl if (cl) { 159 1.1 fvdl if (madefd == TRUE) { 160 1.1 fvdl /* 161 1.1 fvdl * The fd should be closed while destroying the handle. 162 1.1 fvdl */ 163 1.6 christos (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); 164 1.1 fvdl *sockp = fd; 165 1.1 fvdl } 166 1.1 fvdl (void) freenetconfigent(nconf); 167 1.1 fvdl mutex_unlock(&rpcsoc_lock); 168 1.1 fvdl return (cl); 169 1.1 fvdl } 170 1.1 fvdl goto err; 171 1.1 fvdl 172 1.1 fvdl syserror: 173 1.1 fvdl rpc_createerr.cf_stat = RPC_SYSTEMERROR; 174 1.1 fvdl rpc_createerr.cf_error.re_errno = errno; 175 1.1 fvdl 176 1.1 fvdl err: if (madefd == TRUE) 177 1.1 fvdl (void) close(fd); 178 1.1 fvdl (void) freenetconfigent(nconf); 179 1.1 fvdl mutex_unlock(&rpcsoc_lock); 180 1.6 christos return (NULL); 181 1.1 fvdl } 182 1.1 fvdl 183 1.1 fvdl CLIENT * 184 1.16 abs clntudp_bufcreate(struct sockaddr_in *raddr, u_long prog, u_long vers, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz) 185 1.1 fvdl { 186 1.1 fvdl CLIENT *cl; 187 1.1 fvdl 188 1.7 lukem _DIAGASSERT(raddr != NULL); 189 1.7 lukem _DIAGASSERT(sockp != NULL); 190 1.7 lukem 191 1.6 christos cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, 192 1.6 christos sendsz, recvsz, "udp"); 193 1.6 christos if (cl == NULL) { 194 1.6 christos return (NULL); 195 1.1 fvdl } 196 1.6 christos (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, (char *)(void *)&wait); 197 1.1 fvdl return (cl); 198 1.1 fvdl } 199 1.1 fvdl 200 1.1 fvdl CLIENT * 201 1.16 abs clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version, 202 1.16 abs struct timeval wait, int *sockp) 203 1.1 fvdl { 204 1.1 fvdl return clntudp_bufcreate(raddr, program, version, wait, sockp, 205 1.1 fvdl UDPMSGSIZE, UDPMSGSIZE); 206 1.1 fvdl } 207 1.1 fvdl 208 1.1 fvdl CLIENT * 209 1.16 abs clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, 210 1.16 abs u_int sendsz, u_int recvsz) 211 1.1 fvdl { 212 1.6 christos return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, 213 1.6 christos sendsz, recvsz, "tcp"); 214 1.1 fvdl } 215 1.1 fvdl 216 1.1 fvdl CLIENT * 217 1.14 matt clntraw_create(u_long prog, u_long vers) 218 1.1 fvdl { 219 1.6 christos return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers); 220 1.1 fvdl } 221 1.1 fvdl 222 1.1 fvdl /* 223 1.1 fvdl * A common server create routine 224 1.1 fvdl */ 225 1.1 fvdl static SVCXPRT * 226 1.14 matt svc_com_create(int fd, u_int sendsize, u_int recvsize, const char *netid) 227 1.1 fvdl { 228 1.1 fvdl struct netconfig *nconf; 229 1.1 fvdl SVCXPRT *svc; 230 1.1 fvdl int madefd = FALSE; 231 1.1 fvdl int port; 232 1.8 lukem struct sockaddr_in sccsin; 233 1.1 fvdl 234 1.7 lukem _DIAGASSERT(netid != NULL); 235 1.7 lukem 236 1.1 fvdl if ((nconf = __rpc_getconfip(netid)) == NULL) { 237 1.1 fvdl (void) syslog(LOG_ERR, "Could not get %s transport", netid); 238 1.6 christos return (NULL); 239 1.1 fvdl } 240 1.1 fvdl if (fd == RPC_ANYSOCK) { 241 1.1 fvdl fd = __rpc_nconf2fd(nconf); 242 1.1 fvdl if (fd == -1) { 243 1.1 fvdl (void) freenetconfigent(nconf); 244 1.1 fvdl (void) syslog(LOG_ERR, 245 1.1 fvdl "svc%s_create: could not open connection", netid); 246 1.6 christos return (NULL); 247 1.1 fvdl } 248 1.1 fvdl madefd = TRUE; 249 1.1 fvdl } 250 1.1 fvdl 251 1.8 lukem memset(&sccsin, 0, sizeof sccsin); 252 1.8 lukem sccsin.sin_family = AF_INET; 253 1.19 christos (void)bindresvport(fd, &sccsin); 254 1.23 christos 255 1.23 christos switch (nconf->nc_semantics) { 256 1.23 christos case NC_TPI_COTS: 257 1.23 christos case NC_TPI_COTS_ORD: 258 1.23 christos if (listen(fd, SOMAXCONN) == -1) { 259 1.23 christos (void) syslog(LOG_ERR, 260 1.23 christos "svc%s_create: listen(2) failed: %s", 261 1.23 christos netid, strerror(errno)); 262 1.23 christos (void) freenetconfigent(nconf); 263 1.23 christos goto out; 264 1.23 christos } 265 1.23 christos break; 266 1.23 christos default: 267 1.23 christos break; 268 1.22 tron } 269 1.23 christos 270 1.6 christos svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); 271 1.1 fvdl (void) freenetconfigent(nconf); 272 1.20 christos if (svc == NULL) 273 1.20 christos goto out; 274 1.1 fvdl port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); 275 1.1 fvdl svc->xp_port = ntohs(port); 276 1.20 christos return svc; 277 1.20 christos out: 278 1.20 christos if (madefd) 279 1.20 christos (void) close(fd); 280 1.20 christos return NULL; 281 1.1 fvdl } 282 1.1 fvdl 283 1.1 fvdl SVCXPRT * 284 1.16 abs svctcp_create(int fd, u_int sendsize, u_int recvsize) 285 1.1 fvdl { 286 1.1 fvdl return svc_com_create(fd, sendsize, recvsize, "tcp"); 287 1.1 fvdl } 288 1.1 fvdl 289 1.1 fvdl SVCXPRT * 290 1.16 abs svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz) 291 1.1 fvdl { 292 1.1 fvdl return svc_com_create(fd, sendsz, recvsz, "udp"); 293 1.1 fvdl } 294 1.1 fvdl 295 1.1 fvdl SVCXPRT * 296 1.16 abs svcfd_create(int fd, u_int sendsize, u_int recvsize) 297 1.1 fvdl { 298 1.1 fvdl return svc_fd_create(fd, sendsize, recvsize); 299 1.1 fvdl } 300 1.1 fvdl 301 1.1 fvdl 302 1.1 fvdl SVCXPRT * 303 1.16 abs svcudp_create(int fd) 304 1.1 fvdl { 305 1.1 fvdl return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp"); 306 1.1 fvdl } 307 1.1 fvdl 308 1.1 fvdl SVCXPRT * 309 1.15 christos svcraw_create(void) 310 1.1 fvdl { 311 1.1 fvdl return svc_raw_create(); 312 1.1 fvdl } 313 1.1 fvdl 314 1.1 fvdl int 315 1.16 abs get_myaddress(struct sockaddr_in *addr) 316 1.1 fvdl { 317 1.7 lukem 318 1.7 lukem _DIAGASSERT(addr != NULL); 319 1.7 lukem 320 1.1 fvdl memset((void *) addr, 0, sizeof(*addr)); 321 1.1 fvdl addr->sin_family = AF_INET; 322 1.1 fvdl addr->sin_port = htons(PMAPPORT); 323 1.1 fvdl addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 324 1.1 fvdl return (0); 325 1.1 fvdl } 326 1.1 fvdl 327 1.1 fvdl /* 328 1.1 fvdl * For connectionless "udp" transport. Obsoleted by rpc_call(). 329 1.1 fvdl */ 330 1.1 fvdl int 331 1.14 matt callrpc(char *host, int prognum, int versnum, int procnum, 332 1.14 matt xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 333 1.1 fvdl { 334 1.6 christos return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum, 335 1.6 christos (rpcproc_t)procnum, inproc, in, outproc, out, "udp"); 336 1.1 fvdl } 337 1.1 fvdl 338 1.1 fvdl /* 339 1.1 fvdl * For connectionless kind of transport. Obsoleted by rpc_reg() 340 1.1 fvdl */ 341 1.1 fvdl int 342 1.14 matt registerrpc(int prognum, int versnum, int procnum, 343 1.14 matt char *(*progname)(char [UDPMSGSIZE]), 344 1.14 matt xdrproc_t inproc, xdrproc_t outproc) 345 1.1 fvdl { 346 1.6 christos return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum, 347 1.12 christos (rpcproc_t)procnum, progname, inproc, outproc, __UNCONST("udp")); 348 1.1 fvdl } 349 1.1 fvdl 350 1.1 fvdl /* 351 1.1 fvdl * All the following clnt_broadcast stuff is convulated; it supports 352 1.1 fvdl * the earlier calling style of the callback function 353 1.1 fvdl */ 354 1.10 thorpej #ifdef _REENTRANT 355 1.1 fvdl static thread_key_t clnt_broadcast_key; 356 1.1 fvdl #endif 357 1.1 fvdl static resultproc_t clnt_broadcast_result_main; 358 1.1 fvdl 359 1.1 fvdl /* 360 1.1 fvdl * Need to translate the netbuf address into sockaddr_in address. 361 1.1 fvdl * Dont care about netid here. 362 1.1 fvdl */ 363 1.1 fvdl /* ARGSUSED */ 364 1.1 fvdl static bool_t 365 1.14 matt rpc_wrap_bcast( 366 1.14 matt char *resultp, /* results of the call */ 367 1.14 matt struct netbuf *addr, /* address of the guy who responded */ 368 1.14 matt struct netconfig *nconf) /* Netconf of the transport */ 369 1.1 fvdl { 370 1.1 fvdl resultproc_t clnt_broadcast_result; 371 1.7 lukem 372 1.7 lukem _DIAGASSERT(resultp != NULL); 373 1.7 lukem _DIAGASSERT(addr != NULL); 374 1.7 lukem _DIAGASSERT(nconf != NULL); 375 1.1 fvdl 376 1.1 fvdl if (strcmp(nconf->nc_netid, "udp")) 377 1.1 fvdl return (FALSE); 378 1.10 thorpej #ifdef _REENTRANT 379 1.10 thorpej if (__isthreaded == 0) 380 1.1 fvdl clnt_broadcast_result = clnt_broadcast_result_main; 381 1.1 fvdl else 382 1.10 thorpej clnt_broadcast_result = thr_getspecific(clnt_broadcast_key); 383 1.1 fvdl #else 384 1.1 fvdl clnt_broadcast_result = clnt_broadcast_result_main; 385 1.1 fvdl #endif 386 1.1 fvdl return (*clnt_broadcast_result)(resultp, 387 1.1 fvdl (struct sockaddr_in *)addr->buf); 388 1.1 fvdl } 389 1.1 fvdl 390 1.10 thorpej #ifdef _REENTRANT 391 1.10 thorpej static once_t clnt_broadcast_once = ONCE_INITIALIZER; 392 1.10 thorpej 393 1.10 thorpej static void 394 1.10 thorpej clnt_broadcast_setup(void) 395 1.10 thorpej { 396 1.10 thorpej 397 1.10 thorpej thr_keycreate(&clnt_broadcast_key, free); 398 1.10 thorpej } 399 1.10 thorpej #endif 400 1.10 thorpej 401 1.1 fvdl /* 402 1.1 fvdl * Broadcasts on UDP transport. Obsoleted by rpc_broadcast(). 403 1.1 fvdl */ 404 1.1 fvdl enum clnt_stat 405 1.14 matt clnt_broadcast( 406 1.14 matt u_long prog, /* program number */ 407 1.14 matt u_long vers, /* version number */ 408 1.14 matt u_long proc, /* procedure number */ 409 1.14 matt xdrproc_t xargs, /* xdr routine for args */ 410 1.14 matt caddr_t argsp, /* pointer to args */ 411 1.14 matt xdrproc_t xresults, /* xdr routine for results */ 412 1.14 matt caddr_t resultsp, /* pointer to results */ 413 1.14 matt resultproc_t eachresult) /* call with each result obtained */ 414 1.1 fvdl { 415 1.10 thorpej #ifdef _REENTRANT 416 1.10 thorpej if (__isthreaded == 0) 417 1.1 fvdl clnt_broadcast_result_main = eachresult; 418 1.1 fvdl else { 419 1.10 thorpej thr_once(&clnt_broadcast_once, clnt_broadcast_setup); 420 1.1 fvdl thr_setspecific(clnt_broadcast_key, (void *) eachresult); 421 1.1 fvdl } 422 1.1 fvdl #else 423 1.1 fvdl clnt_broadcast_result_main = eachresult; 424 1.1 fvdl #endif 425 1.6 christos return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers, 426 1.6 christos (rpcproc_t)proc, xargs, argsp, xresults, resultsp, 427 1.6 christos (resultproc_t) rpc_wrap_bcast, "udp"); 428 1.1 fvdl } 429 1.1 fvdl 430 1.1 fvdl #endif /* PORTMAP */ 431