1 /* $NetBSD: rpc_soc.c,v 1.4 2000/06/04 04:35:13 thorpej 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 #if 0 42 #if !defined(lint) && defined(SCCSIDS) 43 static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro"; 44 #endif 45 #endif 46 47 #ifdef PORTMAP 48 /* 49 * rpc_soc.c 50 * 51 * The backward compatibility routines for the earlier implementation 52 * of RPC, where the only transports supported were tcp/ip and udp/ip. 53 * Based on berkeley socket abstraction, now implemented on the top 54 * of TLI/Streams 55 */ 56 57 #include "namespace.h" 58 #include "reentrant.h" 59 #include <sys/types.h> 60 #include <sys/socket.h> 61 #include <stdio.h> 62 #include <rpc/rpc.h> 63 #include <rpc/pmap_clnt.h> 64 #include <rpc/pmap_prot.h> 65 #include <netinet/in.h> 66 #include <netdb.h> 67 #include <errno.h> 68 #include <syslog.h> 69 #include <stdlib.h> 70 #include <string.h> 71 #include <unistd.h> 72 73 #include "rpc_com.h" 74 75 #ifdef __weak_alias 76 __weak_alias(clntudp_bufcreate,_clntudp_bufcreate) 77 __weak_alias(clntudp_create,_clntudp_create) 78 __weak_alias(clnttcp_create,_clnttcp_create) 79 __weak_alias(clntraw_create,_clntraw_create) 80 __weak_alias(get_myaddress,_get_myaddress) 81 __weak_alias(svcfd_create,_svcfd_create) 82 __weak_alias(svcudp_bufcreate,_svcudp_bufcreate) 83 __weak_alias(svcudp_create,_svcudp_create) 84 __weak_alias(svctcp_create,_svctcp_create) 85 __weak_alias(svcraw_create,_svcraw_create) 86 __weak_alias(callrpc,_callrpc) 87 __weak_alias(registerrpc,_registerrpc) 88 __weak_alias(clnt_broadcast,_clnt_broadcast) 89 #endif 90 91 #ifdef __REENT 92 extern mutex_t rpcsoc_lock; 93 #endif 94 95 static CLIENT *clnt_com_create __P((struct sockaddr_in *, rpcprog_t, rpcvers_t, 96 int *, u_int, u_int, char *)); 97 static SVCXPRT *svc_com_create __P((int, u_int, u_int, char *)); 98 static bool_t rpc_wrap_bcast __P((char *, struct netbuf *, struct netconfig *)); 99 100 /* 101 * A common clnt create routine 102 */ 103 static CLIENT * 104 clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, tp) 105 struct sockaddr_in *raddr; 106 rpcprog_t prog; 107 rpcvers_t vers; 108 int *sockp; 109 u_int sendsz; 110 u_int recvsz; 111 char *tp; 112 { 113 CLIENT *cl; 114 int madefd = FALSE; 115 int fd = *sockp; 116 struct netconfig *nconf; 117 struct netbuf bindaddr; 118 119 mutex_lock(&rpcsoc_lock); 120 if ((nconf = __rpc_getconfip(tp)) == NULL) { 121 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 122 mutex_unlock(&rpcsoc_lock); 123 return ((CLIENT *)NULL); 124 } 125 if (fd == RPC_ANYSOCK) { 126 fd = __rpc_nconf2fd(nconf); 127 if (fd == -1) 128 goto syserror; 129 madefd = TRUE; 130 } 131 132 if (raddr->sin_port == 0) { 133 u_int proto; 134 u_short sport; 135 136 mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ 137 proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; 138 sport = pmap_getport(raddr, prog, vers, proto); 139 if (sport == 0) { 140 goto err; 141 } 142 raddr->sin_port = htons(sport); 143 mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ 144 } 145 146 /* Transform sockaddr_in to netbuf */ 147 bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); 148 bindaddr.buf = raddr; 149 150 bindresvport(fd, NULL); 151 cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, 152 sendsz, recvsz); 153 if (cl) { 154 if (madefd == TRUE) { 155 /* 156 * The fd should be closed while destroying the handle. 157 */ 158 (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, (char *)NULL); 159 *sockp = fd; 160 } 161 (void) freenetconfigent(nconf); 162 mutex_unlock(&rpcsoc_lock); 163 return (cl); 164 } 165 goto err; 166 167 syserror: 168 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 169 rpc_createerr.cf_error.re_errno = errno; 170 171 err: if (madefd == TRUE) 172 (void) close(fd); 173 (void) freenetconfigent(nconf); 174 mutex_unlock(&rpcsoc_lock); 175 return ((CLIENT *)NULL); 176 } 177 178 CLIENT * 179 clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz) 180 register struct sockaddr_in *raddr; 181 u_long prog; 182 u_long vers; 183 struct timeval wait; 184 int *sockp; 185 u_int sendsz; 186 u_int recvsz; 187 { 188 CLIENT *cl; 189 190 cl = clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, "udp"); 191 if (cl == (CLIENT *)NULL) { 192 return ((CLIENT *)NULL); 193 } 194 (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, (char *)&wait); 195 return (cl); 196 } 197 198 CLIENT * 199 clntudp_create(raddr, program, version, wait, sockp) 200 struct sockaddr_in *raddr; 201 u_long program; 202 u_long version; 203 struct timeval wait; 204 int *sockp; 205 { 206 return clntudp_bufcreate(raddr, program, version, wait, sockp, 207 UDPMSGSIZE, UDPMSGSIZE); 208 } 209 210 CLIENT * 211 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) 212 struct sockaddr_in *raddr; 213 u_long prog; 214 u_long vers; 215 register int *sockp; 216 u_int sendsz; 217 u_int recvsz; 218 { 219 return clnt_com_create(raddr, prog, vers, sockp, sendsz, 220 recvsz, "tcp"); 221 } 222 223 CLIENT * 224 clntraw_create(prog, vers) 225 u_long prog; 226 u_long vers; 227 { 228 return clnt_raw_create(prog, vers); 229 } 230 231 /* 232 * A common server create routine 233 */ 234 static SVCXPRT * 235 svc_com_create(fd, sendsize, recvsize, netid) 236 register int fd; 237 u_int sendsize; 238 u_int recvsize; 239 char *netid; 240 { 241 struct netconfig *nconf; 242 SVCXPRT *svc; 243 int madefd = FALSE; 244 int port; 245 struct sockaddr_in sin; 246 247 if ((nconf = __rpc_getconfip(netid)) == NULL) { 248 (void) syslog(LOG_ERR, "Could not get %s transport", netid); 249 return ((SVCXPRT *)NULL); 250 } 251 if (fd == RPC_ANYSOCK) { 252 fd = __rpc_nconf2fd(nconf); 253 if (fd == -1) { 254 (void) freenetconfigent(nconf); 255 (void) syslog(LOG_ERR, 256 "svc%s_create: could not open connection", netid); 257 return ((SVCXPRT *)NULL); 258 } 259 madefd = TRUE; 260 } 261 262 memset(&sin, 0, sizeof sin); 263 sin.sin_family = AF_INET; 264 bindresvport(fd, &sin); 265 svc = svc_tli_create(fd, nconf, (struct t_bind *)NULL, 266 sendsize, recvsize); 267 (void) freenetconfigent(nconf); 268 if (svc == (SVCXPRT *)NULL) { 269 if (madefd) 270 (void) close(fd); 271 return ((SVCXPRT *)NULL); 272 } 273 port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); 274 svc->xp_port = ntohs(port); 275 return (svc); 276 } 277 278 SVCXPRT * 279 svctcp_create(fd, sendsize, recvsize) 280 register int fd; 281 u_int sendsize; 282 u_int recvsize; 283 { 284 return svc_com_create(fd, sendsize, recvsize, "tcp"); 285 } 286 287 SVCXPRT * 288 svcudp_bufcreate(fd, sendsz, recvsz) 289 register int fd; 290 u_int sendsz, recvsz; 291 { 292 return svc_com_create(fd, sendsz, recvsz, "udp"); 293 } 294 295 SVCXPRT * 296 svcfd_create(fd, sendsize, recvsize) 297 int fd; 298 u_int sendsize; 299 u_int recvsize; 300 { 301 return svc_fd_create(fd, sendsize, recvsize); 302 } 303 304 305 SVCXPRT * 306 svcudp_create(fd) 307 register int fd; 308 { 309 return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp"); 310 } 311 312 SVCXPRT * 313 svcraw_create() 314 { 315 return svc_raw_create(); 316 } 317 318 int 319 get_myaddress(addr) 320 struct sockaddr_in *addr; 321 { 322 memset((void *) addr, 0, sizeof(*addr)); 323 addr->sin_family = AF_INET; 324 addr->sin_port = htons(PMAPPORT); 325 addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 326 return (0); 327 } 328 329 /* 330 * For connectionless "udp" transport. Obsoleted by rpc_call(). 331 */ 332 int 333 callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) 334 char *host; 335 int prognum, versnum, procnum; 336 xdrproc_t inproc, outproc; 337 char *in, *out; 338 { 339 return (int)rpc_call(host, (u_long)prognum, (u_long)versnum, 340 (u_long)procnum, inproc, in, outproc, out, "udp"); 341 } 342 343 /* 344 * For connectionless kind of transport. Obsoleted by rpc_reg() 345 */ 346 int 347 registerrpc(prognum, versnum, procnum, progname, inproc, outproc) 348 int prognum, versnum, procnum; 349 char *(*progname) __P((char [UDPMSGSIZE])); 350 xdrproc_t inproc, outproc; 351 { 352 return rpc_reg((u_long)prognum, (u_long)versnum, (u_long)procnum, 353 progname, inproc, outproc, "udp"); 354 } 355 356 /* 357 * All the following clnt_broadcast stuff is convulated; it supports 358 * the earlier calling style of the callback function 359 */ 360 #ifdef __REENT 361 static thread_key_t clnt_broadcast_key; 362 #endif 363 static resultproc_t clnt_broadcast_result_main; 364 365 /* 366 * Need to translate the netbuf address into sockaddr_in address. 367 * Dont care about netid here. 368 */ 369 /* ARGSUSED */ 370 static bool_t 371 rpc_wrap_bcast(resultp, addr, nconf) 372 char *resultp; /* results of the call */ 373 struct netbuf *addr; /* address of the guy who responded */ 374 struct netconfig *nconf; /* Netconf of the transport */ 375 { 376 resultproc_t clnt_broadcast_result; 377 378 if (strcmp(nconf->nc_netid, "udp")) 379 return (FALSE); 380 #ifdef __REENT 381 if (_thr_main()) 382 clnt_broadcast_result = clnt_broadcast_result_main; 383 else 384 thr_getspecific(clnt_broadcast_key, 385 (void **) &clnt_broadcast_result); 386 #else 387 clnt_broadcast_result = clnt_broadcast_result_main; 388 #endif 389 return (*clnt_broadcast_result)(resultp, 390 (struct sockaddr_in *)addr->buf); 391 } 392 393 /* 394 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast(). 395 */ 396 enum clnt_stat 397 clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) 398 u_long prog; /* program number */ 399 u_long vers; /* version number */ 400 u_long proc; /* procedure number */ 401 xdrproc_t xargs; /* xdr routine for args */ 402 caddr_t argsp; /* pointer to args */ 403 xdrproc_t xresults; /* xdr routine for results */ 404 caddr_t resultsp; /* pointer to results */ 405 resultproc_t eachresult; /* call with each result obtained */ 406 { 407 #ifdef __REENT 408 extern mutex_t tsd_lock; 409 #endif 410 411 #ifdef __REENT 412 if (_thr_main()) 413 clnt_broadcast_result_main = eachresult; 414 else { 415 if (clnt_broadcast_key == 0) { 416 mutex_lock(&tsd_lock); 417 if (clnt_broadcast_key == 0) 418 thr_keycreate(&clnt_broadcast_key, free); 419 mutex_unlock(&tsd_lock); 420 } 421 thr_setspecific(clnt_broadcast_key, (void *) eachresult); 422 } 423 #else 424 clnt_broadcast_result_main = eachresult; 425 #endif 426 return rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, 427 resultsp, (resultproc_t) rpc_wrap_bcast, "udp"); 428 } 429 430 #endif /* PORTMAP */ 431