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