1 /* $NetBSD: rpc_soc.c,v 1.16 2012/06/25 22:32:45 abs 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.16 2012/06/25 22:32:45 abs 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(struct sockaddr_in *raddr, u_long prog, u_long vers, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz) 186 { 187 CLIENT *cl; 188 189 _DIAGASSERT(raddr != NULL); 190 _DIAGASSERT(sockp != NULL); 191 192 cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, 193 sendsz, recvsz, "udp"); 194 if (cl == NULL) { 195 return (NULL); 196 } 197 (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, (char *)(void *)&wait); 198 return (cl); 199 } 200 201 CLIENT * 202 clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version, 203 struct timeval wait, int *sockp) 204 { 205 return clntudp_bufcreate(raddr, program, version, wait, sockp, 206 UDPMSGSIZE, UDPMSGSIZE); 207 } 208 209 CLIENT * 210 clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, 211 u_int sendsz, u_int recvsz) 212 { 213 return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, 214 sendsz, recvsz, "tcp"); 215 } 216 217 CLIENT * 218 clntraw_create(u_long prog, u_long vers) 219 { 220 return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers); 221 } 222 223 /* 224 * A common server create routine 225 */ 226 static SVCXPRT * 227 svc_com_create(int fd, u_int sendsize, u_int recvsize, const char *netid) 228 { 229 struct netconfig *nconf; 230 SVCXPRT *svc; 231 int madefd = FALSE; 232 int port; 233 struct sockaddr_in sccsin; 234 235 _DIAGASSERT(netid != NULL); 236 237 if ((nconf = __rpc_getconfip(netid)) == NULL) { 238 (void) syslog(LOG_ERR, "Could not get %s transport", netid); 239 return (NULL); 240 } 241 if (fd == RPC_ANYSOCK) { 242 fd = __rpc_nconf2fd(nconf); 243 if (fd == -1) { 244 (void) freenetconfigent(nconf); 245 (void) syslog(LOG_ERR, 246 "svc%s_create: could not open connection", netid); 247 return (NULL); 248 } 249 madefd = TRUE; 250 } 251 252 memset(&sccsin, 0, sizeof sccsin); 253 sccsin.sin_family = AF_INET; 254 bindresvport(fd, &sccsin); 255 listen(fd, SOMAXCONN); 256 svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); 257 (void) freenetconfigent(nconf); 258 if (svc == NULL) { 259 if (madefd) 260 (void) close(fd); 261 return (NULL); 262 } 263 port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); 264 svc->xp_port = ntohs(port); 265 return (svc); 266 } 267 268 SVCXPRT * 269 svctcp_create(int fd, u_int sendsize, u_int recvsize) 270 { 271 return svc_com_create(fd, sendsize, recvsize, "tcp"); 272 } 273 274 SVCXPRT * 275 svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz) 276 { 277 return svc_com_create(fd, sendsz, recvsz, "udp"); 278 } 279 280 SVCXPRT * 281 svcfd_create(int fd, u_int sendsize, u_int recvsize) 282 { 283 return svc_fd_create(fd, sendsize, recvsize); 284 } 285 286 287 SVCXPRT * 288 svcudp_create(int fd) 289 { 290 return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp"); 291 } 292 293 SVCXPRT * 294 svcraw_create(void) 295 { 296 return svc_raw_create(); 297 } 298 299 int 300 get_myaddress(struct sockaddr_in *addr) 301 { 302 303 _DIAGASSERT(addr != NULL); 304 305 memset((void *) addr, 0, sizeof(*addr)); 306 addr->sin_family = AF_INET; 307 addr->sin_port = htons(PMAPPORT); 308 addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 309 return (0); 310 } 311 312 /* 313 * For connectionless "udp" transport. Obsoleted by rpc_call(). 314 */ 315 int 316 callrpc(char *host, int prognum, int versnum, int procnum, 317 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 318 { 319 return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum, 320 (rpcproc_t)procnum, inproc, in, outproc, out, "udp"); 321 } 322 323 /* 324 * For connectionless kind of transport. Obsoleted by rpc_reg() 325 */ 326 int 327 registerrpc(int prognum, int versnum, int procnum, 328 char *(*progname)(char [UDPMSGSIZE]), 329 xdrproc_t inproc, xdrproc_t outproc) 330 { 331 return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum, 332 (rpcproc_t)procnum, progname, inproc, outproc, __UNCONST("udp")); 333 } 334 335 /* 336 * All the following clnt_broadcast stuff is convulated; it supports 337 * the earlier calling style of the callback function 338 */ 339 #ifdef _REENTRANT 340 static thread_key_t clnt_broadcast_key; 341 #endif 342 static resultproc_t clnt_broadcast_result_main; 343 344 /* 345 * Need to translate the netbuf address into sockaddr_in address. 346 * Dont care about netid here. 347 */ 348 /* ARGSUSED */ 349 static bool_t 350 rpc_wrap_bcast( 351 char *resultp, /* results of the call */ 352 struct netbuf *addr, /* address of the guy who responded */ 353 struct netconfig *nconf) /* Netconf of the transport */ 354 { 355 resultproc_t clnt_broadcast_result; 356 357 _DIAGASSERT(resultp != NULL); 358 _DIAGASSERT(addr != NULL); 359 _DIAGASSERT(nconf != NULL); 360 361 if (strcmp(nconf->nc_netid, "udp")) 362 return (FALSE); 363 #ifdef _REENTRANT 364 if (__isthreaded == 0) 365 clnt_broadcast_result = clnt_broadcast_result_main; 366 else 367 clnt_broadcast_result = thr_getspecific(clnt_broadcast_key); 368 #else 369 clnt_broadcast_result = clnt_broadcast_result_main; 370 #endif 371 return (*clnt_broadcast_result)(resultp, 372 (struct sockaddr_in *)addr->buf); 373 } 374 375 #ifdef _REENTRANT 376 static once_t clnt_broadcast_once = ONCE_INITIALIZER; 377 378 static void 379 clnt_broadcast_setup(void) 380 { 381 382 thr_keycreate(&clnt_broadcast_key, free); 383 } 384 #endif 385 386 /* 387 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast(). 388 */ 389 enum clnt_stat 390 clnt_broadcast( 391 u_long prog, /* program number */ 392 u_long vers, /* version number */ 393 u_long proc, /* procedure number */ 394 xdrproc_t xargs, /* xdr routine for args */ 395 caddr_t argsp, /* pointer to args */ 396 xdrproc_t xresults, /* xdr routine for results */ 397 caddr_t resultsp, /* pointer to results */ 398 resultproc_t eachresult) /* call with each result obtained */ 399 { 400 #ifdef _REENTRANT 401 if (__isthreaded == 0) 402 clnt_broadcast_result_main = eachresult; 403 else { 404 thr_once(&clnt_broadcast_once, clnt_broadcast_setup); 405 thr_setspecific(clnt_broadcast_key, (void *) eachresult); 406 } 407 #else 408 clnt_broadcast_result_main = eachresult; 409 #endif 410 return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers, 411 (rpcproc_t)proc, xargs, argsp, xresults, resultsp, 412 (resultproc_t) rpc_wrap_bcast, "udp"); 413 } 414 415 #endif /* PORTMAP */ 416