pmap_rmt.c revision 71579
11901Swollman/* 21901Swollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 31901Swollman * unrestricted use provided that this legend is included on all tape 41901Swollman * media and as a part of the software program in whole or part. Users 51901Swollman * may copy or modify Sun RPC without charge, but are not authorized 61901Swollman * to license or distribute it to anyone else except as part of a product or 71901Swollman * program developed by the user. 88870Srgrimes * 91901Swollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 101901Swollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 111901Swollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 128870Srgrimes * 131901Swollman * Sun RPC is provided with no support and without any obligation on the 141901Swollman * part of Sun Microsystems, Inc. to assist in its use, correction, 151901Swollman * modification or enhancement. 168870Srgrimes * 171901Swollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 181901Swollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 191901Swollman * OR ANY PART THEREOF. 208870Srgrimes * 211901Swollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue 221901Swollman * or profits or other special, indirect and consequential damages, even if 231901Swollman * Sun has been advised of the possibility of such damages. 248870Srgrimes * 251901Swollman * Sun Microsystems, Inc. 261901Swollman * 2550 Garcia Avenue 271901Swollman * Mountain View, California 94043 281901Swollman */ 291901Swollman 301901Swollman#if defined(LIBC_SCCS) && !defined(lint) 311901Swollman/*static char *sccsid = "from: @(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";*/ 321901Swollman/*static char *sccsid = "from: @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC";*/ 3350476Speterstatic char *rcsid = "$FreeBSD: head/lib/libc/rpc/pmap_rmt.c 71579 2001-01-24 13:01:12Z deischen $"; 341901Swollman#endif 351901Swollman 361901Swollman/* 371901Swollman * pmap_rmt.c 381901Swollman * Client interface to pmap rpc service. 391901Swollman * remote call and broadcast service 401901Swollman * 411901Swollman * Copyright (C) 1984, Sun Microsystems, Inc. 421901Swollman */ 431901Swollman 4471579Sdeischen#include "namespace.h" 451901Swollman#include <rpc/rpc.h> 461901Swollman#include <rpc/pmap_prot.h> 471901Swollman#include <rpc/pmap_clnt.h> 481901Swollman#include <rpc/pmap_rmt.h> 491901Swollman#include <sys/socket.h> 501901Swollman#include <stdio.h> 5121081Speter#include <stdlib.h> 5211666Sphk#include <unistd.h> 531901Swollman#include <errno.h> 5411666Sphk#include <string.h> 551901Swollman#include <net/if.h> 561901Swollman#include <sys/ioctl.h> 571901Swollman#include <arpa/inet.h> 5871579Sdeischen#include "un-namespace.h" 5971579Sdeischen 601901Swollman#define MAX_BROADCAST_SIZE 1400 611901Swollman 621901Swollmanstatic struct timeval timeout = { 3, 0 }; 631901Swollman 641901Swollman/* 651901Swollman * pmapper remote-call-service interface. 661901Swollman * This routine is used to call the pmapper remote call service 671901Swollman * which will look up a service program in the port maps, and then 681901Swollman * remotely call that routine with the given parameters. This allows 691901Swollman * programs to do a lookup and call in one step. 701901Swollman*/ 711901Swollmanenum clnt_stat 721901Swollmanpmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr) 731901Swollman struct sockaddr_in *addr; 741901Swollman u_long prog, vers, proc; 751901Swollman xdrproc_t xdrargs, xdrres; 761901Swollman caddr_t argsp, resp; 771901Swollman struct timeval tout; 781901Swollman u_long *port_ptr; 791901Swollman{ 801901Swollman int socket = -1; 811901Swollman register CLIENT *client; 821901Swollman struct rmtcallargs a; 831901Swollman struct rmtcallres r; 841901Swollman enum clnt_stat stat; 851901Swollman 861901Swollman addr->sin_port = htons(PMAPPORT); 871901Swollman client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket); 881901Swollman if (client != (CLIENT *)NULL) { 891901Swollman a.prog = prog; 901901Swollman a.vers = vers; 911901Swollman a.proc = proc; 921901Swollman a.args_ptr = argsp; 931901Swollman a.xdr_args = xdrargs; 941901Swollman r.port_ptr = port_ptr; 951901Swollman r.results_ptr = resp; 961901Swollman r.xdr_results = xdrres; 971901Swollman stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a, 981901Swollman xdr_rmtcallres, &r, tout); 991901Swollman CLNT_DESTROY(client); 1001901Swollman } else { 1011901Swollman stat = RPC_FAILED; 1021901Swollman } 10321081Speter if (socket != -1) 10456698Sjasone (void)_close(socket); 1051901Swollman addr->sin_port = 0; 1061901Swollman return (stat); 1071901Swollman} 1081901Swollman 1091901Swollman 1101901Swollman/* 1111901Swollman * XDR remote call arguments 1121901Swollman * written for XDR_ENCODE direction only 1131901Swollman */ 1141901Swollmanbool_t 1151901Swollmanxdr_rmtcall_args(xdrs, cap) 1161901Swollman register XDR *xdrs; 1171901Swollman register struct rmtcallargs *cap; 1181901Swollman{ 1191901Swollman u_int lenposition, argposition, position; 1201901Swollman 1211901Swollman if (xdr_u_long(xdrs, &(cap->prog)) && 1221901Swollman xdr_u_long(xdrs, &(cap->vers)) && 1231901Swollman xdr_u_long(xdrs, &(cap->proc))) { 1241901Swollman lenposition = XDR_GETPOS(xdrs); 1251901Swollman if (! xdr_u_long(xdrs, &(cap->arglen))) 1261901Swollman return (FALSE); 1271901Swollman argposition = XDR_GETPOS(xdrs); 1281901Swollman if (! (*(cap->xdr_args))(xdrs, cap->args_ptr)) 1291901Swollman return (FALSE); 1301901Swollman position = XDR_GETPOS(xdrs); 1311901Swollman cap->arglen = (u_long)position - (u_long)argposition; 1321901Swollman XDR_SETPOS(xdrs, lenposition); 1331901Swollman if (! xdr_u_long(xdrs, &(cap->arglen))) 1341901Swollman return (FALSE); 1351901Swollman XDR_SETPOS(xdrs, position); 1361901Swollman return (TRUE); 1371901Swollman } 1381901Swollman return (FALSE); 1391901Swollman} 1401901Swollman 1411901Swollman/* 1421901Swollman * XDR remote call results 1431901Swollman * written for XDR_DECODE direction only 1441901Swollman */ 1451901Swollmanbool_t 1461901Swollmanxdr_rmtcallres(xdrs, crp) 1471901Swollman register XDR *xdrs; 1481901Swollman register struct rmtcallres *crp; 1491901Swollman{ 1501901Swollman caddr_t port_ptr; 1511901Swollman 1521901Swollman port_ptr = (caddr_t)crp->port_ptr; 1531901Swollman if (xdr_reference(xdrs, &port_ptr, sizeof (u_long), 1541901Swollman xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { 1551901Swollman crp->port_ptr = (u_long *)port_ptr; 1561901Swollman return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); 1571901Swollman } 1581901Swollman return (FALSE); 1591901Swollman} 1601901Swollman 1611901Swollman 1621901Swollman/* 1631901Swollman * The following is kludged-up support for simple rpc broadcasts. 1648870Srgrimes * Someday a large, complicated system will replace these trivial 1651901Swollman * routines which only support udp/ip . 1661901Swollman */ 1671901Swollman 1681901Swollmanstatic int 1691901Swollmangetbroadcastnets(addrs, sock, buf) 1701901Swollman struct in_addr *addrs; 1711901Swollman int sock; /* any valid socket will do */ 1721901Swollman char *buf; /* why allocxate more when we can use existing... */ 1731901Swollman{ 1741901Swollman struct ifconf ifc; 17521081Speter struct ifreq ifreq, *ifr; 1761901Swollman struct sockaddr_in *sin; 17714659Sguido struct in_addr addr; 17821081Speter char *cp, *cplim; 17921081Speter int n, i = 0; 1801901Swollman 1811901Swollman ifc.ifc_len = UDPMSGSIZE; 1821901Swollman ifc.ifc_buf = buf; 18371579Sdeischen if (_ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { 1841901Swollman perror("broadcast: ioctl (get interface configuration)"); 1851901Swollman return (0); 1861901Swollman } 1871901Swollman#define max(a, b) (a > b ? a : b) 1881901Swollman#define size(p) max((p).sa_len, sizeof(p)) 1891901Swollman cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ 1901901Swollman for (cp = buf; cp < cplim; 1911901Swollman cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { 1921901Swollman ifr = (struct ifreq *)cp; 1931901Swollman if (ifr->ifr_addr.sa_family != AF_INET) 1941901Swollman continue; 19557728Sshin memcpy(&ifreq, ifr, sizeof(ifreq)); 19671579Sdeischen if (_ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 1971901Swollman perror("broadcast: ioctl (get interface flags)"); 1981901Swollman continue; 1991901Swollman } 2001901Swollman if ((ifreq.ifr_flags & IFF_BROADCAST) && 2011901Swollman (ifreq.ifr_flags & IFF_UP)) { 2021901Swollman sin = (struct sockaddr_in *)&ifr->ifr_addr; 2031901Swollman#ifdef SIOCGIFBRDADDR /* 4.3BSD */ 20471579Sdeischen if (_ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 20514659Sguido addr = 2061901Swollman inet_makeaddr(inet_netof(sin->sin_addr), 2071901Swollman INADDR_ANY); 2081901Swollman } else { 20914659Sguido addr = ((struct sockaddr_in*) 2101901Swollman &ifreq.ifr_addr)->sin_addr; 2111901Swollman } 2121901Swollman#else /* 4.2 BSD */ 21314659Sguido addr = inet_makeaddr(inet_netof(sin->sin_addr), 2141901Swollman INADDR_ANY); 2151901Swollman#endif 21614659Sguido for (n=i-1; n>=0; n--) { 21714659Sguido if (addr.s_addr == addrs[n].s_addr) 21814659Sguido break; 21914659Sguido } 22014659Sguido if (n<0) { 22114659Sguido addrs[i++] = addr; 22214659Sguido } 2231901Swollman } 2241901Swollman } 2251901Swollman return (i); 2261901Swollman} 2271901Swollman 2281901Swollmantypedef bool_t (*resultproc_t)(); 2291901Swollman 2308870Srgrimesenum clnt_stat 2311901Swollmanclnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) 2321901Swollman u_long prog; /* program number */ 2331901Swollman u_long vers; /* version number */ 2341901Swollman u_long proc; /* procedure number */ 2351901Swollman xdrproc_t xargs; /* xdr routine for args */ 2361901Swollman caddr_t argsp; /* pointer to args */ 2371901Swollman xdrproc_t xresults; /* xdr routine for results */ 2381901Swollman caddr_t resultsp; /* pointer to results */ 2391901Swollman resultproc_t eachresult; /* call with each result obtained */ 2401901Swollman{ 2411901Swollman enum clnt_stat stat; 2421901Swollman AUTH *unix_auth = authunix_create_default(); 2431901Swollman XDR xdr_stream; 2441901Swollman register XDR *xdrs = &xdr_stream; 2451901Swollman int outlen, inlen, fromlen, nets; 2461901Swollman register int sock; 2471901Swollman int on = 1; 24821081Speter fd_set *fds, readfds; 2491901Swollman register int i; 2501901Swollman bool_t done = FALSE; 2511901Swollman register u_long xid; 2521901Swollman u_long port; 2531901Swollman struct in_addr addrs[20]; 2541901Swollman struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ 2551901Swollman struct rmtcallargs a; 2561901Swollman struct rmtcallres r; 2571901Swollman struct rpc_msg msg; 25821081Speter struct timeval t, tv; 2591901Swollman char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; 26021081Speter static u_int32_t disrupt; 2611901Swollman 26221081Speter if (disrupt == 0) 26321081Speter disrupt = (u_int32_t)(long)resultsp; 26421081Speter 2651901Swollman /* 2661901Swollman * initialization: create a socket, a broadcast address, and 2671901Swollman * preserialize the arguments into a send buffer. 2681901Swollman */ 26971579Sdeischen if ((sock = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 2701901Swollman perror("Cannot create socket for broadcast rpc"); 2711901Swollman stat = RPC_CANTSEND; 2721901Swollman goto done_broad; 2731901Swollman } 2741901Swollman#ifdef SO_BROADCAST 27571579Sdeischen if (_setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 2761901Swollman perror("Cannot set socket option SO_BROADCAST"); 2771901Swollman stat = RPC_CANTSEND; 2781901Swollman goto done_broad; 2791901Swollman } 2801901Swollman#endif /* def SO_BROADCAST */ 28121081Speter if (sock + 1 > FD_SETSIZE) { 28221081Speter int bytes = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); 28321081Speter fds = (fd_set *)malloc(bytes); 28421081Speter if (fds == NULL) { 28521081Speter stat = RPC_CANTSEND; 28621081Speter goto done_broad; 28721081Speter } 28821081Speter memset(fds, 0, bytes); 28921081Speter } else { 29021081Speter fds = &readfds; 29121081Speter FD_ZERO(fds); 29221081Speter } 29321081Speter 2941901Swollman nets = getbroadcastnets(addrs, sock, inbuf); 29521081Speter memset(&baddr, 0, sizeof (baddr)); 29617540Speter baddr.sin_len = sizeof(struct sockaddr_in); 2971901Swollman baddr.sin_family = AF_INET; 2981901Swollman baddr.sin_port = htons(PMAPPORT); 2991901Swollman baddr.sin_addr.s_addr = htonl(INADDR_ANY); 3001901Swollman (void)gettimeofday(&t, (struct timezone *)0); 30121081Speter msg.rm_xid = xid = (++disrupt) ^ getpid() ^ t.tv_sec ^ t.tv_usec; 3021901Swollman t.tv_usec = 0; 3031901Swollman msg.rm_direction = CALL; 3041901Swollman msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 3051901Swollman msg.rm_call.cb_prog = PMAPPROG; 3061901Swollman msg.rm_call.cb_vers = PMAPVERS; 3071901Swollman msg.rm_call.cb_proc = PMAPPROC_CALLIT; 3081901Swollman msg.rm_call.cb_cred = unix_auth->ah_cred; 3091901Swollman msg.rm_call.cb_verf = unix_auth->ah_verf; 3101901Swollman a.prog = prog; 3111901Swollman a.vers = vers; 3121901Swollman a.proc = proc; 3131901Swollman a.xdr_args = xargs; 3141901Swollman a.args_ptr = argsp; 3151901Swollman r.port_ptr = &port; 3161901Swollman r.xdr_results = xresults; 3171901Swollman r.results_ptr = resultsp; 3181901Swollman xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); 3191901Swollman if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { 3201901Swollman stat = RPC_CANTENCODEARGS; 3211901Swollman goto done_broad; 3221901Swollman } 3231901Swollman outlen = (int)xdr_getpos(xdrs); 3241901Swollman xdr_destroy(xdrs); 3251901Swollman /* 3261901Swollman * Basic loop: broadcast a packet and wait a while for response(s). 3271901Swollman * The response timeout grows larger per iteration. 32821081Speter * 32921081Speter * XXX This will loop about 5 times the stop. If there are 33021081Speter * lots of signals being received by the process it will quit 33121081Speter * send them all in one quick burst, not paying attention to 33221081Speter * the intended function of sending them slowly over half a 33321081Speter * minute or so 3341901Swollman */ 3351901Swollman for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { 3361901Swollman for (i = 0; i < nets; i++) { 3371901Swollman baddr.sin_addr = addrs[i]; 33871579Sdeischen if (_sendto(sock, outbuf, outlen, 0, 3391901Swollman (struct sockaddr *)&baddr, 3401901Swollman sizeof (struct sockaddr)) != outlen) { 3411901Swollman perror("Cannot send broadcast packet"); 3421901Swollman stat = RPC_CANTSEND; 3431901Swollman goto done_broad; 3441901Swollman } 3451901Swollman } 3461901Swollman if (eachresult == NULL) { 3471901Swollman stat = RPC_SUCCESS; 3481901Swollman goto done_broad; 3491901Swollman } 3501901Swollman recv_again: 3511901Swollman msg.acpted_rply.ar_verf = _null_auth; 3521901Swollman msg.acpted_rply.ar_results.where = (caddr_t)&r; 35321081Speter msg.acpted_rply.ar_results.proc = xdr_rmtcallres; 35421081Speter /* XXX we know the other bits are still clear */ 35521081Speter FD_SET(sock, fds); 35671579Sdeischen tv = t; /* for _select() that copies back */ 35771579Sdeischen switch (_select(sock + 1, fds, NULL, NULL, &tv)) { 3581901Swollman 3591901Swollman case 0: /* timed out */ 3601901Swollman stat = RPC_TIMEDOUT; 3611901Swollman continue; 3621901Swollman 3631901Swollman case -1: /* some kind of error */ 3641901Swollman if (errno == EINTR) 3651901Swollman goto recv_again; 3661901Swollman perror("Broadcast select problem"); 3671901Swollman stat = RPC_CANTRECV; 3681901Swollman goto done_broad; 3691901Swollman 3701901Swollman } /* end of select results switch */ 3711901Swollman try_again: 3721901Swollman fromlen = sizeof(struct sockaddr); 37371579Sdeischen inlen = _recvfrom(sock, inbuf, UDPMSGSIZE, 0, 3741901Swollman (struct sockaddr *)&raddr, &fromlen); 3751901Swollman if (inlen < 0) { 3761901Swollman if (errno == EINTR) 3771901Swollman goto try_again; 3781901Swollman perror("Cannot receive reply to broadcast"); 3791901Swollman stat = RPC_CANTRECV; 3801901Swollman goto done_broad; 3811901Swollman } 38221081Speter if (inlen < sizeof(u_int32_t)) 3831901Swollman goto recv_again; 3841901Swollman /* 3851901Swollman * see if reply transaction id matches sent id. 3861901Swollman * If so, decode the results. 3871901Swollman */ 3881901Swollman xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); 3891901Swollman if (xdr_replymsg(xdrs, &msg)) { 3901901Swollman if ((msg.rm_xid == xid) && 3911901Swollman (msg.rm_reply.rp_stat == MSG_ACCEPTED) && 3921901Swollman (msg.acpted_rply.ar_stat == SUCCESS)) { 3931901Swollman raddr.sin_port = htons((u_short)port); 3941901Swollman done = (*eachresult)(resultsp, &raddr); 3951901Swollman } 3961901Swollman /* otherwise, we just ignore the errors ... */ 3971901Swollman } 3981901Swollman xdrs->x_op = XDR_FREE; 3991901Swollman msg.acpted_rply.ar_results.proc = xdr_void; 4001901Swollman (void)xdr_replymsg(xdrs, &msg); 4011901Swollman (void)(*xresults)(xdrs, resultsp); 4021901Swollman xdr_destroy(xdrs); 4031901Swollman if (done) { 4041901Swollman stat = RPC_SUCCESS; 4051901Swollman goto done_broad; 4061901Swollman } else { 4071901Swollman goto recv_again; 4081901Swollman } 4091901Swollman } 4101901Swollmandone_broad: 41121081Speter if (fds != &readfds) 41221081Speter free(fds); 41321081Speter if (sock >= 0) 41456698Sjasone (void)_close(sock); 4151901Swollman AUTH_DESTROY(unix_auth); 4161901Swollman return (stat); 4171901Swollman} 4181901Swollman 419