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