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 46 static 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 99 static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t, 100 int *, u_int, u_int, const char *); 101 static SVCXPRT *svc_com_create(int, u_int, u_int, const char *); 102 static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *); 103 104 /* 105 * A common clnt create routine 106 */ 107 static CLIENT * 108 clnt_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 172 syserror: 173 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 174 rpc_createerr.cf_error.re_errno = errno; 175 176 err: if (madefd == TRUE) 177 (void) close(fd); 178 (void) freenetconfigent(nconf); 179 mutex_unlock(&rpcsoc_lock); 180 return (NULL); 181 } 182 183 CLIENT * 184 clntudp_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 200 CLIENT * 201 clntudp_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 208 CLIENT * 209 clnttcp_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 216 CLIENT * 217 clntraw_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 */ 225 static SVCXPRT * 226 svc_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; 277 out: 278 if (madefd) 279 (void) close(fd); 280 return NULL; 281 } 282 283 SVCXPRT * 284 svctcp_create(int fd, u_int sendsize, u_int recvsize) 285 { 286 return svc_com_create(fd, sendsize, recvsize, "tcp"); 287 } 288 289 SVCXPRT * 290 svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz) 291 { 292 return svc_com_create(fd, sendsz, recvsz, "udp"); 293 } 294 295 SVCXPRT * 296 svcfd_create(int fd, u_int sendsize, u_int recvsize) 297 { 298 return svc_fd_create(fd, sendsize, recvsize); 299 } 300 301 302 SVCXPRT * 303 svcudp_create(int fd) 304 { 305 return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp"); 306 } 307 308 SVCXPRT * 309 svcraw_create(void) 310 { 311 return svc_raw_create(); 312 } 313 314 int 315 get_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 */ 330 int 331 callrpc(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 */ 341 int 342 registerrpc(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 355 static thread_key_t clnt_broadcast_key; 356 #endif 357 static 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 */ 364 static bool_t 365 rpc_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 391 static once_t clnt_broadcast_once = ONCE_INITIALIZER; 392 393 static void 394 clnt_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 */ 404 enum clnt_stat 405 clnt_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